Assignment1_Divide_and_Conquer
1 数组中的第k大元素(Leetcode.215)
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: end if
3: left = 0
4: n = len(nums)
5: right = n-1
6: index = quick_sort(nums, left, right)
7: while index != n-k do # determine if it is the Kth largest element
8: if index > n-k then right = index-1
9: else left = index+1
10: end if
11: index = quick_sort(nums, left, right)
12: end while
13: return nums[index]
function quick_sort(nums, left, right)
# quicksort determines the index of an element
1: pivot = nums[left]
2: while left < right do
3: while left < right & nums[right] >= pivot do
4: right = right - 1
5: end while
6: nums[left] = nums[right]
7: while left < right & nums[left] <= pivot do
8: left = left + 1
9: end while
10: nums[right] = nums[left]
11: end while
12: nums[left] = pivot
13: return left
一般,快排是对参考元素两边都进行递归,但在解决这个问题时只考虑参考元素的一边,只对一边进行递归,根据索引与(n-k)的比较选择对其中一遍进行递归。第一次划分需要遍历约n个数,第二次需要遍历约n/2个数,......,这样递归下去,结果趋近于2n,所以该算法的时间复杂度整体上为\( O(N) \)。
2 找到一棵树的最小结点
Consider an n-node complete binary tree T, where n = 2d − 1 for some d. Each node v of
T is labeled with a real number xv. You may assume that the real numbers labeling the nodes
are all distinct. A node v of T is a local minimum if the label xv is less than the label xw for
all nodes w that are joined to v by an edge.
You are given such a complete binary tree T, but the labeling is only specified in the following: implicit way: for each node v, you can determine the value xv by probing the node v.Show how to find a local minimum of T using only O(logn) probes to the nodes of T.
找到一棵树的最小节点,需要找到根节点与根节点的两个孩子节点的最小值,三者比较:如果最小值是根节点,那么就返回该节点,否则递归查找孩子中值较小的那一个对应的子树。https://wenku.baidu.com/view/...
伪码 pseudo-code
function tree_local_min(T,w)
1: if w has no child then
2: return w
3: else
4: l = left child of w
5: r = right child of w
6: if w < l & w < r then
7: return w
8: else
9: v = min(l,r)
10: tree_local_min(T,v)
11: end if
12: end if
递归查找子树中最小值的时间复杂度为\( O(logn) \),算法其他比较部分的复杂度为\( O(1) \),因此整个算法的复杂度为\( O(logn) \)。
3 最大子序和(Leetcode.53)
Given an integer array, one or more consecutive integers in the array form a sub-array. Find
the maximum value of the sum of all subarrays.Please give an algorithm with O(nlogn) complexity.
对数组进行遍历,找出当前最大子序和sum,如果 sum>0 说明sum对结果有增益,保留当前值并加上当前遍历的数组值;如果 sum<0 说明sum对结果无增益,舍弃,sum更新为当前遍历的数组值。每次得到的sum与结果res比较取最大值,直到循环数组完毕。
伪码 pseudo-code
function maxSubArray(nums)
1: sum = 0 # the current max sub-array
2: res = nums[0]
3: for i in nums do
4: if sum > 0 then
5: sum = sum + i
6: else sum = i # discard the result without gain
7: end if
8: res = max(sum,res)
9: end for
10: return res
算法的时间复杂度即为对数组进行遍历的时间复杂度,因此为\( O(n) \)。
4 在排序数组中查找元素的第一个和最后一个位置(Leetcode.34)
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 failure
2: end if
3: left = 0 # find the left boundary of target
4: right = len(nums)-1
5: while left < right do
6: mid = (left+right)/2
7: if nums[mid] >= target then right = mid
8: else left = mid+1
9: end if
10: end while
11: if nums[right] != target then return [-1,-1] # find the failure
12: end if
13: L = right
14: left = 0 # Find the right boundary of target
15: right = len(nums)-1
16: while left < right do
17: mid = (left+right+1)/2 # prevent dead loops, mid needs add 1
18: if nums[mid] <= target return [-1,-1] left = mid
19: else right = mid-1
20: end if
21: end while
22: R = right
23: return [L,R]
二分查找的时间复杂度为\( O(logn) \),会进行两次二分查找,因此时间复杂度为\( O(logn) \)。
5 凸多边形划分为三角形
Given a convex polygon with n vertices, we can divide it into several separated pieces, such
that every piece is a triangle. When n = 4, there are two different ways to divide the polygon;
When n = 5, there are five different ways.Give an algorithm that decides how many ways we can divide a convex polygon with n vertices into triangles.
凸多边形划分为三角形的不同划分方法数,把一个正凸N边形的每个顶点按顺时针编号。取顶点1、n和i(2<=i<=(n-1))就可以构成一个三角形S,凸N边形就被分成三部分:一个三角形S、一个i边形和一个n+1-i边形。因此,凸N边形分为三角形的总数就等于i边形的分法总数乘以n+1-i边形的分法总数,还要在i分别取2,3,……,n-1时都累加起来。
伪码 pseudo-code
function PolyCutToTri(n)
Initialize an array with all zeros and arr[2]=1, arr[3]=1
if arr[n] != 0 then //arr[n] has record
return arr[n];
end if
sum = 0;
for i = 2 to n-1 do
sum += PolyCutToTri(i) * PolyCutToTri(n + 1 -i);
end for
arr[n] = sum; //record the data
return sum;
6 合并K个升序链表(Leetcode.23)
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 queue
1: head = ListNode(0) # first node
2: p = head
3: q = PriorityQueue()
4: for l in lists do
5: if l is not None then q.put((l.val,l)) # all heads join the queue
6: end if
7: end for
8: while q is not empty do
9: val, node = q.get() # get the smallest value and node
10: p.next = ListNode(val)
11: p = p.next
12: node = node.next
13: if node is not None then q.put((node.val,node))
# enter header of list
14: end if
15: end while
16: return head.next
k个链表有k个头结点,优先队列中包含k个结点,优先队列插入删除的时间复杂度为\( O(logk) \),总共有nk个结点需要被插入删除,所以时间复杂度为\( O(knlogk) \)。
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。