Assignment1_Divide_and_Conquer

1 Divide and Conquer

  Given an integer array nums and an integer k, please return the k-th largest element in the
array. Your algorithm’s runtime complexity must be in the order of \( O(n) \), prove the correctness and analyze the complexity.(k is much smaller than n, n is the length of the array.)

  利用疾速排序的办法,每一次快排都能够确定一个元素的地位,即pivot的索引,pivot右边的都小于等于它,左边的都大于等于它。这样就能够将pivot的索引与(n-k)比拟,如果相等,那么该索引对应的值就是数组中第k大的数;如果索引小于(n-k),那么第k大的数在该索引的左边,下一轮快排便是对索引的右侧元素进行排序;如果索引大于(n-k),那么第k大的数在该索引的右边,下一轮快排便是对索引的左侧元素进行排序。

pseudo-code

function kth_largest_element(nums,k)1:  if len(nums)<1 | k < 0 | k > len(nums) then return    2:  left = 03:  n = len(nums)4:  right = n-15:  index = quick_sort(nums, left, right)6:  while index != n-k do  # determine if it is the Kth largest element7:      if index > n-k then right = index-1      8:      if index < n-k then left = index+1     9:      index = quick_sort(nums, left, right)10:  return nums[index]  function quick_sort(nums, left, right)# quicksort determines the index of an element1:  pivot = nums[left]2:  while left < right do3:      while left < right & nums[right] >= pivot do4:          right = right - 15:      nums[left] = nums[right]6:      while left < right & nums[left] <= pivot do7:          left = left + 18:      nums[right] = nums[left]9:  nums[left] = pivot10: return left

  个别,快排是对参考元素两边都进行递归,但在解决这个问题时只思考参考元素的一边,只对一边进行递归,依据索引与(n-k)的比拟抉择对其中一遍进行递归。第一次划分须要遍历约n个数,第二次须要遍历约n/2个数,......,这样递归上来,后果趋近于2n,所以该算法的工夫复杂度整体上为\( O(N) \)。

4 Divide and Conquer

  Given an array of integers nums sorted in ascending order, find the starting and ending
position of a given target value. If the target is not found in the array, return [-1, -1]. For
example, if the array is [5, 7, 7, 8, 8, 10] and the target is 8, then the output should be [3, 4].
  Your algorithm’s runtime complexity must be in the order of $O(log n)$, prove the correctness
and analyze the complexity.

  查找枯燥递增的整数数组的其中一个元素的开始地位和完结地位,能够利用二分法来实现。两次二分:第一次查找第一个>=target的地位,即元素最左边界;第二次查找最初一个<=target的地位,即最右边界。查找胜利则返回两个地位下标,否则返回[-1,-1]。

pseudo-code

function searchIndex(nums, target)1:  if len(nums)<1 then return [-1,-1]  # find the failure2:  # find the left boundary of target3:  left = 04:  right = len(nums)-15:  while left < right do6:      mid = (left+right)/27:      if nums[mid] >= target then right = mid8:      else left = mid+19:  if nums[right] != target then return [-1,-1] # find the failure10: L = right11: # Find the right boundary of target12: left = 013: right = len(nums)-114: while left < right do15:     mid = (left+right+1)/2  # prevent dead loops, mid needs add 116:     if nums[mid] <= target return [-1,-1] left = mid17:     else right = mid-118: R = right    19: return [L,R] 

  二分查找的工夫复杂度为\( O(logn) \),会进行两次二分查找,因而工夫复杂度为\( O(logn) \)。

6 Divide and Conquer

  Given an array of k linked-lists lists, each linked-list is sorted in ascending order. Given an
\( O(knlogk) \)algorithm to merge all the linked-lists into one sorted linked-list. (Note that the
length of a linked-lists is n)

  将k个升序链表合并为一个升序链表。对于mergeKLists函数,将这k个升序链表的头结点输出到优先队列中,只有队列不为空,优先队列便会选取其中最小的结点,而后输入最小结点将其退出到新链表中,而这个最小结点的链表的头结点又输出到队列,保障队列中含每个链表的结点,始终循环直到队列为空,最终新链表按升序排列好这k个链表,可证实算法的正确性。

pseudo-code

function mergeKLists(lists)# Compare all linked-lists' header and take the smallest -- Using priority queue1:  head = ListNode(0)  # first node2:  p = head3:  q = PriorityQueue()4:  for l in lists do5:      if l is not None then q.put((l.val,l))  # all heads join the queue6:  while q is not empty do7:      val, node = q.get()  # get the smallest value and node8:      p.next = ListNode(val)9:      p = p.next10:     node = node.next11:     if node is not None then q.put((node.val,node))  # enter header of list12: return head.next

  k个链表有k个头结点,优先队列中蕴含k个结点,优先队列插入删除的工夫复杂度为\( O(logk) \),总共有nk个结点须要被插入删除,所以工夫复杂度为\( O(knlogk) \)。