leetcode: 4. 寻找两个正序数组的中位数
题目描述
给定两个大小分别为 m 和 n 的正序(从小到大)数组 nums1 和 nums2。请你找出并返回这两个正序数组的 中位数 。
算法的时间复杂度应该为 O(log (m+n)) 。
示例
输入: nums1 = [1,3], nums2 = [2]
输出: 2.00000
解释: 合并数组 = [1,2,3] ,中位数 2
解题思路
中位数 统一奇偶数处理:
- 奇数:
(n / 2) + 1orn / 2 + 1 - 偶数:
(n / 2 + n / 2 + 1) / 2, n / 2 == (n + 1) / 2
find找到两个正序中第k小的数:
- 保证nums1大小 < nums2,避免额外判断和处理。
- nums1大小为0,直接从nums2中拿
- k为1时,取两个数组首元素中更小的那个
- 二分处理,每次舍去 k/2 的元素:
- nums1取k一半或者较小一半的元素大小,nums2取另一半
- 如果nums1拿到的最后一个元素 大于 nums2拿到的,那么第k大的元素肯定不在nums2拿到的这部分 舍去
- 反之,舍去nums1拿到的这部分(相等的情况舍去小的部分)
完整代码:
class Solution {
public double findMedianSortedArrays(int[] nums1, int[] nums2) {
int n = nums1.length + nums2.length;
int l = find(nums1, 0, nums2, 0, (n + 1) / 2);
int r = find(nums1, 0, nums2, 0, n / 2 + 1);
return (l + r) / 2.0;
}
int find (int[] nums1, int start1, int[] nums2, int start2, int target) {
int len1 = nums1.length - start1, len2 = nums2.length - start2;
if (len1 > len2) {
return find(nums2, start2, nums1, start1, target);
}
if (0 == len1) return nums2[start2 + target - 1];
if (1 == target) return Math.min(nums1[start1], nums2[start2]);
int l = len1 < target / 2 ? nums1.length - 1 : start1 + target / 2 - 1;
int r = start2 + (target + 1) / 2 - 1;
if (nums1[l] > nums2[r]) {
return find(nums1, start1, nums2, r + 1, target - (target + 1) / 2);
}
else {
return find(nums1, l + 1, nums2, start2, target - target / 2);
}
}
}