模板
每次将问题的可行域减半的思想。
int binary_search1(int l, int r) {
while (l < r) {
int mid = l + r >> 1;
if (check(mid)) r = mid;
else l = mid + 1;
}
return r;
}
int binary_search2(int l, int r) {
while (l < r) {
int mid = l + r + 1 >> 1;
if (check(mid)) l = mid;
else r = mid - 1;
}
return l;
}
练习整理
Leetcode 4. Median of Two Sorted Arrays
简单的做法是先merge two sorted arrays,再取median,复杂度 O ( m + n ) O(m + n) O(m+n),但是题目要求时间复杂度 O ( l o g ( m + n ) ) O(log(m + n)) O(log(m+n))。
将题目转化成取两个sorted arrays的第k
个元素,k = (nums1.size() + nums2.size()) / 2
。
比较nums1[k/2]
和nums2[k/2]
:
- 当
nums1[k/2] < nums2[k/2]
,说明第k
小的元素不可能在nums1[0 ~ k/2]
中,所以可以将其删除,同时更新k -= 删除的长度
。 - 同理,
nums1[k/2] > nums2[k/2]
时,第k
小的元素不可能在nums2[0 ~ k/2]
中,将其删除。 - 当
nums1[k/2] == nums2[k/2]
时,任意删除nums1
或nums2
的前k/2
个元素。
递归地进行上述操作,当有一个array为空,或k == 1
时,得到解。
每次递归都能将nums1
或nums2
的长度减半,时间复杂度O(log(m + n))
。
class Solution {
public:
double findMedianSortedArrays(vector<int>& nums1, vector<int>& nums2) {
int total = nums1.size() + nums2.size();
if (total % 2 == 0) {
int left = find(nums1, 0, nums2, 0, total / 2);
int right = find(nums1, 0, nums2, 0, total / 2 + 1);
return (left + right) / 2.0;
} else {
return find(nums1, 0, nums2, 0, total / 2 + 1);
}
}
// Returns the kth element of nums1[i:] and nums2[j:]
int find(vector<int>& nums1, int i, vector<int>& nums2, int j, int k) {
// Let nums1[i:] be the smaller array.
if (nums1.size() - i > nums2.size() - j) return find(nums2, j, nums1, i, k);
// Corner case: nums1[i:] is empty.
if (nums1.size() == i) return nums2[j + k - 1];
// Corner case: k = 1.
if (k == 1) return min(nums1[i], nums2[j]);
int si = min(i + k / 2, (int)nums1.size()), sj = j + k - k / 2;
if (nums1[si - 1] > nums2[sj - 1]) {
return find(nums1, i, nums2, sj, k - (sj - j));
} else {
return find(nums1, si, nums2, j, k - (si - i));
}
}
};