LeetCode每日一刷-寻找两个正序数组的中位数
4. 寻找两个正序数组的中位数
给定两个大小为 m 和 n 的正序(从小到大)数组 nums1 和 nums2。请你找出并返回这两个正序数组的中位数。
进阶:你能设计一个时间复杂度为 O(log (m+n)) 的算法解决此问题吗?
首先,中位数是按顺序排列的一组数据中居于中间位置的数,如果观察值有偶数个,通常取最中间的两个数值的平均数作为中位数。
最直观的方法就是排序和双指针。
- 使用归并的方式,合并两个有序数组,得到一个大的有序数组。大的有序数组的中间位置的元素,即为中位数。
- 不需要合并两个有序数组,只要找到中位数的位置即可。由于两个数组的长度已知,因此中位数对应的两个数组的下标之和也是已知的。维护两个指针,初始时分别指向两个数组的下标 00 的位置,每次将指向较小值的指针后移一位(如果一个指针已经到达数组末尾,则只需要移动另一个数组的指针),直到到达中位数的位置。
其中归并排序算法忽略,给出双指针算法,能通过LeetCode测试,时间复杂度O(m+n)。
首先是怎么将奇数和偶数的情况合并一下。
用 len 表示合并后数组的长度,如果是奇数,我们需要知道第 (len+1)/2 个数就可以了,如果遍历的话需要遍历 int(len/2 ) + 1 次。如果是偶数,我们需要知道第 len/2和 len/2+1 个数,也是需要遍历 len/2+1 次。所以遍历的话,奇数和偶数都是 len/2+1 次。
返回中位数的话,奇数需要最后一次遍历的结果就可以了,偶数需要最后一次和上一次遍历的结果。所以我们用两个变量 left 和 right,right 保存当前循环的结果,在每次循环前将 right 的值赋给 left。这样在最后一次循环的时候,left 将得到 right 的值,也就是上一次循环的结果,接下来 right 更新为最后一次的结果。
循环中该怎么写,什么时候 A 数组后移,什么时候 B 数组后移。用 aStart 和 bStart 分别表示当前指向 A 数组和 B 数组的位置。如果 aStart 还没有到最后并且此时 A 位置的数字小于 B 位置的数组,那么就可以后移了。也就是aStart<m&&A[aStart]< B[bStart]。
但如果 B 数组此刻已经没有数字了,继续取数字 B[ bStart ],则会越界,所以判断下 bStart 是否大于数组长度了,这样 || 后边的就不会执行了,也就不会导致错误了,所以增加为 aStart<m&&(bStart) >= n||A[aStart]<B[bStart]) 。
1 public double FindMedianSortedArrays(int[] A, int[] B) 2 { 3 int m = A.Length; 4 int n = B.Length; 5 int len = m + n; 6 int aStart = 0, bStart = 0; 7 int left = 0, right = 0; 8 for (int i = 0; i <= len/2; i++) 9 { 10 left = right; 11 if (aStart < m && (bStart >= n || A[aStart] < B[bStart])) 12 { 13 right = A[aStart]; 14 aStart++; 15 } 16 else 17 { 18 right = B[bStart]; 19 bStart++; 20 } 21 } 22 if ((m + n) % 2 == 0) 23 { 24 return (left + right) / 2.0; 25 } 26 else 27 { 28 return right; 29 } 30 }
但是要达到最优解O(log(m+n)),看到log,明显需要用到二分的方法。(未完待续)
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/median-of-two-sorted-arrays
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。