[leetcode] 4-寻找两个有序数组的中位数
2019-10-21 22:15
323 查看
给定两个大小为 m 和 n 的有序数组 nums1 和 nums2。
请你找出这两个有序数组的中位数,并且要求算法的时间复杂度为 O(log(m + n))。
你可以假设 nums1 和 nums2 不会同时为空。
Input: nums1 = [1, 3]
nums2 = [2]
Output: 则中位数是 2.0
2.思路
1.外排
由于数组是有序的,因此可以用外排,将两个数组marge成另外的数组help[]。从有序数组help中找出中位数就是一件简单的事了。(缺点是需要额外的空间来构造一个有序的新数组。)
实际时间复杂度为O(m+n),空间复杂度为O(m+n)。
2.双指针法
定义两个指针分别指向两个数组的开头。若数组总数num为奇数,则查找第num/2个数;若总数为偶数,则找那两个/2.
(这里不提供代码)
时间复杂度O(m+n),空间复杂度O(1)。
3. 二分法查找
一般时间复杂度为O(logn)的算法,都是需要用到分治思想(且一般为二分)。
两个有序数组求中位数,问题一般化为,求两个有序数组的第k个数,当k = (m+n)/2时为原问题的解。
怎么求第k个数?分别求出第一个和第二个数组的第 k / 2个数 a 和 b,然后比较 a 和 b,当a < b ,说明第 k 个数位于 a数组的第 k / 2个数后半段,或者b数组的 第 k / 2 个数前半段,问题规模缩小了一半,然后递归处理就行。
时间复杂度O(log m+n),空间复杂度O(1)
3.题解
外排法
class Solution { public double findMedianSortedArrays(int[] nums1, int[] nums2) { int m=nums1.length; int n=nums2.length; int i=0; int j=0; int k=0; int[] help=new int[n+m]; while(i<=m-1&&j<=n-1){ help[k++]=nums1[i]<=nums2[j]?nums1[i++]:nums2[j++]; } while(i<m){ help[k++]=nums1[i++]; } while(j<n){ help[k++]=nums2[j++]; } k=help.length; if(k%2==0){ return (help[k/2]+help[k/2-1])/2.0; } else{ return help[k/2]*1.0; } } }
二分查找法
class Solution { public double findMedianSortedArrays(int[] nums1, int[] nums2) { int m = nums1.length; int n = nums2.length; //处理任何一个nums为空数组的情况 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; //总数为奇数,找第 total / 2 + 1 个数 if ((total & 1) == 1) { return find_kth(nums1, 0, nums2, 0, total / 2 + 1); } //总数为偶数,找第 total / 2 个数和第total / 2 + 1个数的平均值 return (find_kth(nums1, 0, nums2, 0, total / 2) + find_kth(nums1, 0, nums2, 0, total / 2 + 1)) / 2.0; } //寻找a 和 b 数组中,第k个数字 double find_kth(int[] a, int a_begin, int[] b, int b_begin, int k) { //当a 或 b 超过数组长度,则第k个数为另外一个数组第k个数 if (a_begin >= a.length) return b[b_begin + k - 1]; if (b_begin >= b.length) return a[a_begin + k - 1]; //k为1时,两数组最小的那个为第一个数 if (k == 1) return Math.min(a[a_begin], b[b_begin]); int mid_a = Integer.MAX_VALUE; int mid_b = Integer.MAX_VALUE; //mid_a / mid_b 分别表示 a数组、b数组中第 k / 2 个数 if (a_begin + k / 2 - 1 < a.length) mid_a = a[a_begin + k / 2 - 1]; if (b_begin + k / 2 - 1 < b.length) mid_b = b[b_begin + k / 2 - 1]; //如果a数组的第 k / 2 个数小于b数组的第 k / 2 个数,表示总的第 k 个数位于 a的第k / 2个数的后半段,或者是b的第 k / 2个数的前半段 //由于范围缩小了 k / 2 个数,此时总的第 k 个数实际上等于新的范围内的第 k - k / 2个数,依次递归 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); } }
相关文章推荐
- LeetCode4 寻找两个有序数组的中位数 Median of Two Sorted Arrays
- 【leetcode】4. 寻找两个有序数组的中位数
- 寻找两个有序数组的中位数(LeetCode)
- LeetCode 4 --寻找两个有序数组的中位数--Python
- LeetCode--4. 寻找两个有序数组的中位数(Median of Two Sorted Arrays)
- LeetCode刷题-寻找两个有序数组的中位数
- LeetCode:4. 寻找两个有序数组的中位数(Java)
- [LeetCode]4. 寻找两个有序数组的中位数/C++
- LeetCode:4. 寻找两个有序数组的中位数(Java)
- leetcode4 寻找两个有序数组的中位数 python
- leetcode 寻找两个有序数组的中位数
- leetCode---寻找两个有序数组的中位数
- LeetCode刷题笔记(Java版)----4. 寻找两个有序数组的中位数
- leetcode之数组类之数组的旋转与分治类-----OJ 189/33/81/153/154 数组旋转 旋转数组搜索 88 有序数组合并 4 两个有序数组寻找第K个元素/中位数 35 寻找插入位置
- leetcode第四题:寻找两个有序数组的中位数
- Leetcode-寻找两个有序数组的中位数
- LeetCode 寻找两个有序数组的中位数
- Leetcode:4.寻找两个有序数组的中位数
- leetcode 4.寻找两个有序数组的中位数
- 【LeetCode】第四题:寻找两个有序数组的中位数