LeetCode #4. 寻找两个正序数组的中位数
I. Description:
II. Solution:
version 1
解题思路:
整体思路是将A和B两个数组按照升序合并,最终计算一个有序数组的中位数。此时,需要判断下数组长度的奇偶性。
Code:
- cpp
#include <vector>
class Solution {
public:
double findMedianSortedArrays(vector<int>& nums1, vector<int>& nums2) {
if(nums1.empty()){
int L = nums2.size();
if(L % 2 == 0){
return (nums2[L/2 - 1] + nums2[L/2]) / 2.0;
}
else{
return nums2[L/2];
}
}
if(nums2.empty()){
int L = nums1.size();
if(L % 2 == 0){
return (nums1[L/2 - 1] + nums1[L/2]) / 2.0;
}
else{
return nums1[L/2];
}
}
int L = 0;
int i = 0, j = 0;
int len_nums1 = nums1.size();
int len_nums2 = nums2.size();
// 将两个数组按照非降序合并成一个数组
int s = len_nums1 + len_nums2;
vector<int> nums_merge(s, 0);
while(L != (len_nums1 + len_nums2)){
// i,j其中某个数已经达到数组的长度
if(i == len_nums1){
while(j != len_nums2){
nums_merge[L++] = nums2[j++];
}
break;
}
if(j == len_nums2){
while(i != len_nums1){
nums_merge[L++] = nums1[i++];
}
break;
}
if(nums1[i] < nums2[j]){
nums_merge[L++] = nums1[i++];
}
else{
nums_merge[L++] = nums2[j++];
}
}
// 前面都是为了获得合并后数组的长度
if (L % 2 == 0){
return (nums_merge[L/2 - 1] + nums_merge[L/2]) / 2.0;
}
else{
return nums_merge[L/2];
}
}
};
version 2
解题思路:
分析
v
e
r
s
i
o
n
1
version1
version1 的求解过程可知,我们不必等到把数组A和B合并完成后再去找中位数的位置。通过两个数组的长度
m
+
n
m+n
m+n 可以知道合并后的数组长度,是否可以写一个循环,当遍历到了中位数的位置就将结果返回。方法是可以但对于奇数偶数的分类还是会较为麻烦,能否通过某种方式将奇数偶数统一起来。
假设合并后的数组长度为
l
e
n
len
len。当
l
e
n
len
len 为奇数时,我们需要得到
l
e
n
/
2
len/2
len/2 索引处的值,则需要遍历的次数为
l
e
n
/
2
+
1
len/2+1
len/2+1;当
l
e
n
len
len 为偶数时,我们需要得到
l
e
n
/
2
−
1
len/2-1
len/2−1 和
l
e
n
/
2
len/2
len/2 索引处的值,则依然需要遍历
l
e
n
/
2
+
1
len/2+1
len/2+1 次。所以论遍历的次数,不论奇偶都需要遍历
l
e
n
/
2
+
1
len/2+1
len/2+1 次。
当
l
e
n
len
len 为奇数时,返回中位数只需要返回最后一次遍历的结果。当
l
e
n
len
len 为偶数时,则需要返回最后一次和倒数第二次的遍历结果。这样我们可以设
c
u
r
cur
cur 和
p
r
e
pre
pre 两个变量用来分别记录当前一次和紧挨着的上一次循环遍历的结果,在每次循环开始时,先将
c
u
r
cur
cur 的值赋给
p
r
e
pre
pre ,这样当循环到最后一次遍历时,
p
r
e
pre
pre 得到
c
u
r
cur
cur 的值,即倒数第二次遍历的结果,随后
c
u
r
cur
cur 更新为最后一次的结果。
Code:
- cpp
class Solution {
public:
double findMedianSortedArrays(vector<int>& nums1, vector<int>& nums2) {
int m = nums1.size();
int n = nums2.size();
int len = m + n;
int numTraversal = len/2 + 1; //总共遍历这么多次
//分别用来记录两个数组的当前索引位置
int a = 0, b = 0;
//分别用来存放当前循环遍历的结果和前一次遍历的结果
int cur = 0, pre = 0;
int count = 0;
for(int i = 0; i < numTraversal; i++){
pre = cur;
//需要考虑两个数组有没有到头, 这个判断条件设置的较为巧妙
if(a < m && (b == n || nums1[a] < nums2[b])){
cur = nums1[a++];
}
else{
cur = nums2[b++];
}
}
if(len % 2 == 0){
return (cur + pre) / 2.0;
}
else{
return cur;
}
}
};