LeetCode - 4 寻找两个正序数组的中位数
题目来源
4. 寻找两个正序数组的中位数 - 力扣(LeetCode)
题目描述
给定两个大小分别为 m 和 n 的正序(从小到大)数组 nums1 和 nums2。请你找出并返回这两个正序数组的 中位数 。
算法的时间复杂度应该为 O(log (m+n)) 。
示例 1
输入:nums1 = [1,3], nums2 = [2]
输出:2.00000
解释:合并数组 = [1,2,3] ,中位数 2
示例 2
输入:nums1 = [1,2], nums2 = [3,4]
输出:2.50000
解释:合并数组 = [1,2,3,4] ,中位数 (2 + 3) / 2 = 2.5
提示
- nums1.length == m
- nums2.length == n
- 0 <= m <= 1000
- 0 <= n <= 1000
- 1 <= m + n <= 2000
- -10^6 <= nums1[i], nums2[i] <= 10^6
题目解析
这题目前没有想到 O(log(m+n)) 时间复杂度的解法,后面找机会看看官方题解。
我看到这题,会联想到归并排序里面合并两个有序数组的策略,而本题实际上不需要合并 nums1 和 nums2,只需要模拟合并比较过程即可。
由于我们需要找到 nums1 和 nums2 合并后有序数组的中位数,而中位数就是中间的数,因此我们可以先求出合并后数组的长度 len = nums1.length + nums2.length。
- 如果 len 为奇数,那么中位数就是合并后数组的第 len / 2 的元素
- 如果 len 为偶数,那么中位数就是合并后数组的第 len / 2 和 len / 2 + 1 的元素的平均数
为了代码逻辑简单,我们这里默认合并后数组的中间数有两个,分别记录于 midNum1 和 midNum2。
合并两个有序数组的过程如下:
定义一个变量 k,用于记录已经合并的元素个数,这里我们需要合并 len / 2 + 1 个数
定义变量 i 和 变量 j,分别指向 nums1 和 nums2 的索引位置,初始时都为 0。
我们需要不停地比较 nums1[i] 和 nums2[j],谁更小,则谁先被合并。
当然,也存在某个数组被先一步合并完的情况,此时需要做好越界判断。
- 若 i 越界,即 i >= nums1.length,则 j++
- 若 j 越界,即 j >= nums2.length,则 i++
- 若 nums1[i] <= nums2[j],则 i++
- 若 nums1[i] > nums2[j],则 j++
每发生一次合并,我们需要操作如下:
- midNum1 = midNum2
- 更新 midNum2 为合并的元素值
这样的话,最后 midNum1 和 midNum2 记录的就是最后被合并的两个元素值。
由于我们只合并 len / 2 + 1 次,因此最后合并的两个元素值就是完全合并后的大数组的中间两个元素值。
- 如果 len % 2 == 0,那么结果就是 (midNum1 + midNum2) / 2
- 如果 len % 2 != 0,那么结果就是 midNum2
C源码实现
double findMedianSortedArrays(int* nums1, int nums1Size, int* nums2, int nums2Size) {
int len = nums1Size + nums2Size;
int i = 0;
int j = 0;
int midNum1 = -1;
int midNum2 = -1;
for (int k = 0; k <= len / 2; k++) {
midNum1 = midNum2;
if (i >= nums1Size) {
midNum2 = nums2[j++];
} else if (j >= nums2Size) {
midNum2 = nums1[i++];
} else if (nums1[i] <= nums2[j]) {
midNum2 = nums1[i++];
} else {
midNum2 = nums2[j++];
}
}
if (len % 2 == 0) {
return (midNum1 + midNum2) / 2.0;
} else {
return midNum2;
}
}
C++源码实现
class Solution {
public:
double findMedianSortedArrays(vector<int>& nums1, vector<int>& nums2) {
int len = nums1.size() + nums2.size();
int i = 0;
int j = 0;
int midNum1 = -1;
int midNum2 = -1;
for (int k = 0; k <= len / 2; k++) {
midNum1 = midNum2;
if (i >= nums1.size()) {
midNum2 = nums2[j++];
} else if (j >= nums2.size()) {
midNum2 = nums1[i++];
} else if (nums1[i] <= nums2[j]) {
midNum2 = nums1[i++];
} else {
midNum2 = nums2[j++];
}
}
if (len % 2 == 0) {
return (midNum1 + midNum2) / 2.0;
} else {
return midNum2;
}
}
};
Java源码实现
class Solution {
public double findMedianSortedArrays(int[] nums1, int[] nums2) {
int len = nums1.length + nums2.length;
int i = 0;
int j = 0;
int midNum1 = -1;
int midNum2 = -1;
for (int k = 0; k <= len / 2; k++) {
midNum1 = midNum2;
if (i >= nums1.length) {
midNum2 = nums2[j++];
} else if (j >= nums2.length) {
midNum2 = nums1[i++];
} else if (nums1[i] <= nums2[j]) {
midNum2 = nums1[i++];
} else {
midNum2 = nums2[j++];
}
}
if (len % 2 == 0) {
return (midNum1 + midNum2) / 2.0;
} else {
return midNum2;
}
}
}
Python源码实现
class Solution(object):
def findMedianSortedArrays(self, nums1, nums2):
"""
:type nums1: List[int]
:type nums2: List[int]
:rtype: float
"""
length = len(nums1) + len(nums2)
i = 0
j = 0
midNum1 = -1
midNum2 = -1
for k in range(length // 2 + 1):
midNum1 = midNum2
if i >= len(nums1):
midNum2 = nums2[j]
j += 1
elif j >= len(nums2):
midNum2 = nums1[i];
i += 1
elif nums1[i] <= nums2[j]:
midNum2 = nums1[i];
i += 1
else:
midNum2 = nums2[j]
j += 1
if length % 2 == 0:
return (midNum1 + midNum2) / 2.0
else:
return midNum2
JavaScript源码实现
/**
* @param {number[]} nums1
* @param {number[]} nums2
* @return {number}
*/
var findMedianSortedArrays = function (nums1, nums2) {
const len = nums1.length + nums2.length;
let i = 0;
let j = 0;
let midNum1 = -1;
let midNum2 = -1;
for (let k = 0; k <= len / 2; k++) {
midNum1 = midNum2;
if (i >= nums1.length) {
midNum2 = nums2[j];
j++;
} else if (j >= nums2.length) {
midNum2 = nums1[i];
i++;
} else if (nums1[i] <= nums2[j]) {
midNum2 = nums1[i];
i++;
} else {
midNum2 = nums2[j];
j++;
}
}
if (len % 2 == 0) {
return (midNum1 + midNum2) / 2;
} else {
return midNum2;
}
};