题目来源:https://leetcode-cn.com/problems/median-of-two-sorted-arrays/
大致题意:
给两个升序数组,找出两个数组元素合并后的中位数
思路
这道题等价于求两个数组中第 k 小的数
题目要求 log(m + n) 的复杂度,所以可以用二分
每次比较两个数组第 k/2 个数的大小,将小的元素所在数组的前 k/2 个元素去掉(因为第 k 小的数一定不会在这部分),这样每次去一半,直到有个数组的元素全部去掉或者 k 为 1
为什么较两个数组第 k/2 个数的大小时可以将小的元素所在数组的前 k/2 个元素去掉?
- 假设有数组 A 和 B,若 A[k/2 - 1] 小于 B[k/2 - 1],那么小于 A[k/2] 的元素最多有 A[0] - A[k/2 - 2] 和 B[0] - B[k/2 - 2] 共 k - 2 个元素,即 A[k/2] 一定不是第 k 小的数,所以 A[0] - A[k/2 - 1] 都可以去掉
具体实现时,要注意到遍历索引不能越界,去掉的数组元素应为实际值
public double findMedianSortedArrays(int[] nums1, int[] nums2) {
int m = nums1.length;
int n = nums2.length;
double ans = 0.0;
int k = (m + n) / 2;
// 两个数组合并长度为奇数
if ((m + n) % 2 == 1) {
ans = getKthElement(nums1, nums2, k + 1);
} else {
// 两个数组合并长度为偶数
ans = (getKthElement(nums1, nums2, k) + getKthElement(nums1, nums2, k + 1)) / 2.0;
}
return ans;
}
public int getKthElement(int[] nums1, int[] nums2, int k) {
int idx1 = 0; // 数组 1 的索引
int idx2 = 0; // 数组 2 的索引
int len1 = nums1.length;
int len2 = nums2.length;
while (true) {
// 若有一个数组元素已经全部去掉,直接从另一个中取答案
if (idx1 == len1) {
return nums2[idx2 + k - 1];
}
if (idx2 == len2) {
return nums1[idx1 + k - 1];
}
// 若 k 为 1,则取当前两个数组还未去掉元素中的最小值
if (k == 1) {
return Math.min(nums1[idx1], nums2[idx2]);
}
// 数组目前第 k/2 小的索引
int newIdx1 = Math.min(idx1 + k / 2, len1) - 1;
int newIdx2 = Math.min(idx2 + k / 2, len2) - 1;
// 选择去掉的索引
if (nums1[newIdx1] <= nums2[newIdx2]) {
// 更新 k
k -= newIdx1 - idx1 + 1;
idx1 = newIdx1 + 1;
} else {
k -= newIdx2 - idx2 + 1;
idx2 = newIdx2 + 1;
}
}
}