[LeetCode] Median of Two Sorted Arrays 解题报告
There are two sorted arrays nums1 and nums2 of size m and n respectively. Find the median of the two sorted arrays. The overall run time complexity should be O(log (m+n)).
Subscribe to see which companies asked this question
分析:
这个题目在leetcode 中难度级别为hard。其实如果没有限定复杂度为O(log(m+n)),那么难度就要下降不少。
首先对于中位数这个概念,如果两个数组size 之和为奇数,那么中位数就是中间的那个数;否则中位数是中间两个数相加后的平均值。
- 比较容易想到的方法是采用merge sort 的方法合并两个数组,然后再取中位数,这样的时间复杂度在 O(m+n),不符合题目要求。其实merge sort 的策略只需要遍历((m+n)/2) 个数据就OK了,因为只需要早中位数,不需要完全遍历排序。
- 如果需要在O(log(m+n))下实现,就要考虑到这是个查找问题,对于有序数组的查找借助2分法的策略可以大大减去不必要的操作。这里借助在两个有序数组中find Kth 的思路。
关于两个有序数组的findKth,可以先比较两个数组A[m], B[n]的k/2位置,假设值为A[k/2 - 1] 和 B[k/2 - 1]:
- 如果A[k/2 - 1] == B[k/2 - 1],那么就可以认为找到那个kth value;
- 如果A[k/2 - 1] > B[k/2 - 1],那么可以判断出kth value 不处于B[0]到B[k/2 - 1],即可以去除掉这部分内容后,在剩下的内容中找到(k-k/2)th value;
- 如果A[k/2] < B[k/2],就如同上一个条件一样,可以去除掉部分内容,重新调用findKth 策略.
最终演化为一个递归的策略,每次递归都可以去除一部分内容,并同时缩小K 的值,最终可以找到答案。
递归方案:
- 当A 或 B 是空时,直接返回B[k-1] 或是 A[k-1]
- 当k=1 时,返回 min(A[0], B[0])
- 当A[k/2 - 1] == B[k/2 - 1] 时,返回A[k/2 - 1] 或 B[k/2 - 1]
note: findKth 的K是从1开始,而且要注意K与数组索引之间的关系,小心找到前一个或后一个位置。
实现代码:
Merge Sort 方案:
double merge(int *nums1, int nums1Size, int *nums2, int nums2Size) { double result = 0.0; int totalSize = nums1Size + nums2Size; int mid = totalSize >> 1; int nums1Index = 0; int nums2Index = 0; int *nums = (int *)malloc((mid+1) * sizeof(int)); for (int index = 0; index <= mid; index++) { if (nums1Index >= nums1Size) { nums[index] = nums2[nums2Index++]; } else if (nums2Index >= nums2Size) { nums[index] = nums1[nums1Index++]; } else if (nums1[nums1Index] < nums2[nums2Index]) { nums[index] = nums1[nums1Index++]; } else { nums[index] = nums2[nums2Index++]; } } if ((nums1Size + nums2Size) & 0x01) { result = nums[mid]; } else { result = (nums[mid-1] + nums[mid])/2.0; } free(nums); return result; } double findMedianSortedArrays(int* nums1, int nums1Size, int* nums2, int nums2Size) { return merge(nums1, nums1Size, nums2, nums2Size); }
FindKth 方案:
double findKth(int a[], int m, int b[], int n, int k) { if (m > n) return findKth(b, n, a, m, k); if (m == 0) return b[k - 1]; if (k == 1) return min(a[0], b[0]); int pa = min(k/2, m); int pb = k - pa; if (a[pa-1] < b[pb-1]) return findKth(a+pa, m-pa, b, n, k-pa); else if (a[pa-1] > b[pb-1]) return findKth(a, m, b+pb, n-pb, k-pb); else return a[pa-1]; } double findMedianSortedArrays(int* nums1, int nums1Size, int* nums2, int nums2Size) { int mid = (nums1Size + nums2Size) >> 1; if ((nums1Size + nums2Size) & 0x01) { return findKth(nums1, nums1Size, nums2, nums2Size, mid+1); } else { return (findKth(nums1, nums1Size, nums2, nums2Size, mid) + findKth(nums1, nums1Size, nums2, nums2Size, mid + 1)) / 2.0; } }
在Leetcode 中实际提交时,这两个方案都能达到最优的20ms 结果。