题目: 给定两个大小为 m 和 n 的有序数组 nums1 和 nums2。请你找出这两个有序数组的中位数,并且要求算法的时间复杂度为 O(log(m + n))。你可以假设 nums1 和 nums2 不会同时为空。
题解: 一开始没看到要求时间是log(m + n),直接俩下标标记过去了,时间复杂度是 (m + n) / 2。先贴一下这个版本的代码,不过就算这样LeetCode也给过了= =。
class Solution { public: double findMedianSortedArrays(vector<int>& nums1, vector<int>& nums2) { int n = (int)nums1.size(), m = (int)nums2.size(); int left1 = 0, left2 = 0; int numleft1 = 0, numleft2 = 0; while (left1 + left2 < (n + m) / 2 + 1){ numleft1 = numleft2; if (left1 == n) numleft2 = nums2[left2++]; else if (left2 == m) numleft2 = nums1[left1++]; else { if (nums1[left1] < nums2[left2]) numleft2 = nums1[left1++]; else numleft2 = nums2[left2++]; } } if ((n + m) & 1) return numleft2; else return (double)(numleft1 + numleft2) / 2.0; } };
接下来是log(n + m) 的代码,思路就是二分,从第一个数组找一个位置 x,第二个数组中找一个位置 y,其中 y = (m + n + 2x) / 2,使得找到的x,y左边的数都大于右边的数即可。
class Solution { public: double findMedianSortedArrays(vector<int>& nums1, vector<int>& nums2) { int m = nums1.size(); int n = nums2.size(); if (m == 0) { if (n % 2 != 0) return 1.0 * nums2[n / 2]; return (nums2[n / 2] + nums2[n / 2 - 1]) / 2.0; } if (n == 0) { if (m % 2 != 0) return 1.0 * nums1[m / 2]; return (nums1[m / 2] + nums1[m / 2 - 1]) / 2.0; } int total = m + n; if ((total & 1) == 1) { return find_kth(nums1, 0, nums2, 0, total / 2 + 1); } return (find_kth(nums1, 0, nums2, 0, total / 2) + find_kth(nums1, 0, nums2, 0, total / 2 + 1)) / 2.0; } double find_kth(vector<int>& a, int a_begin, vector<int>& b, int b_begin, int k) { if (a_begin >= a.size()) return b[b_begin + k - 1]; if (b_begin >= b.size()) return a[a_begin + k - 1]; if (k == 1) return min(a[a_begin], b[b_begin]); int mid_a = 0x7fffffff; int mid_b = 0x7fffffff; if (a_begin + k / 2 - 1 < a.size()) mid_a = a[a_begin + k / 2 - 1]; if (b_begin + k / 2 - 1 < b.size()) mid_b = b[b_begin + k / 2 - 1]; if (mid_a < mid_b) return find_kth(a, a_begin + k / 2, b, b_begin, k - k / 2); return find_kth(a, a_begin, b, b_begin + k / 2, k - k / 2); } };