问题描述:给定两个大小为 m 和 n 的有序数组 nums1 和 nums2。找出这两个有序数组的中位数,并且要求算法的时间复杂度为 O(log(m + n))。
思路:
- 暴力求解
.通过直接对数组遍历排序,从新数组中直接计算中位数。
时间复杂度:o(m+n)
空间复杂度:o(m+n)
- 数组遍历
不对数组进行重新组合,直接在遍历过程中计算位置(分奇偶)。
时间复杂度:o(m+n)
空间复杂度:o(1)
- 分支算法—第k小数
将中位数的寻找看成第k小数的寻找,并将奇偶情况转化为同一计算方式(把偶次中位数看成两次)。
时间复杂度:o(log(m + n))
空间复杂度:o(1)
- 分支算法—对半分割思想
对两个数组分别进行切割,每次切除将数组分为两半,并且交叉拼接满足位数相同,直至找到这样的位置使得左边最大小于等于右边最小。
复杂度:与第三种方法相同
//c++
//方法一:暴力求解
class Solution {
public:
double findMedianSortedArrays(vector<int>& nums1, vector<int>& nums2) {
double median = 0.0;
vector<int> num;
int i = 0, j = 0;
int len1 = nums1.size();
int len2 = nums2.size();
while(i < len1 & j < len2){
//比较大小填入新数组
if(nums1[i] <= nums2[j]){
num.push_back(nums1[i]);
++i;
}else{
num.push_back(nums2[j]);
++j;
}
}
//将剩余部分装入
while(j <len2){
num.push_back(nums2[j]);
++j;
}
while(i <len1){
num.push_back(nums1[i]);
++i;
}
//直接寻找中位数
if((len1 +len2)%2)
median = num[floor((len1 + len2)/2.0)];
else
median = (num[(len1 + len2)/2] + num[(len1 + len2)/2 - 1])/2.0;
return median;
}
};
//方法二:数组遍历
class Solution {
public:
double findMedianSortedArrays(vector<int>& nums1, vector<int>& nums2) {
double median = 0.0;
int index1 = 0, index2 = 0;//num1,num2遍历位置
int len1 = nums1.size();
int len2 = nums2.size();
int len = len1 + len2;
int left = -1, right = -1;
//寻找中间位置,left保持上一次位置,当数组和为偶数时并入计算
for(int i = 0; i <= len/2; ++i){
left = right;
if(index1 < len1 && (index2 >= len2 || nums1[index1] < nums2[index2]))
right = nums1[index1++];
else
right = nums2[index2++];
}
//判断奇偶情况
if(len%2)
return right;
else
return (left + right)/2.0;
}
};
//方法三:第k小数
class Solution {
public:
double findMedianSortedArrays(vector<int>& nums1, vector<int>& nums2) {
int len1 = nums1.size();
int len2 = nums2.size();
//当数组和为奇数时下面两数相同,偶数是分别指向中位数左右两个位置
int left = (len1 + len2 + 1)/2;
int right = (len1 + len2 + 2)/2;
//奇偶情况并入计算
return (getKth(nums1, 0, len1-1, nums2, 0, len2-1, left) + getKth(nums1, 0, len1-1, nums2, 0, len2-1, right))/2.0;
}
//求第k小数
int getKth(vector<int>& num1, int left1, int right1, vector<int>& num2, int left2, int right2 , int k){
int size1 = right1 - left1 + 1;
int size2 = right2 - left2 + 1;
//保证第一个数组长度小于第二个
if(size1 > size2) return getKth(num2, left2, right2, num1, left1, right1, k);
//第一个数组筛选完毕,直接进入第二个数组找
if(size1 == 0){
return num2[left2 + k - 1];
}else if(k == 1){
//筛选到最后一位,找两个位置较小的数
return num1[left1] <= num2[left2] ? num1[left1] : num2[left2];
}else{
//更新位置,筛掉较小的一部分数(k/2或数组剩余)
int i = (size1 < k/2 ? size1 : k/2) + left1 - 1;
int j = (size2 < k/2 ? size2 : k/2) + left2 - 1;
//递归筛选至上述基本情况
if(num1[i] <= num2[j])
return getKth(num1, i + 1, right1, num2, left2, right2, k - (i - left1 + 1));
else
return getKth(num1, left1, right1, num2, j + 1, right2, k - (j - left2 + 1));
}
}
};
//方法四:分割思想
class Solution {
public:
double findMedianSortedArrays(vector<int>& nums1, vector<int>& nums2) {
int len1 = nums1.size();
int len2 = nums2.size();
//保证j的范围
if(len1 > len2) return findMedianSortedArrays(nums2, nums1);
int left = 0, right = len1;
while(left <= right){
//找到i, j分别指向的数组位置
int i = (left + right)/2;
int j = (len1 + len2 + 1)/2 - i;
//判断移动方向
if(i < len1 && j > 0 && nums1[i] < nums2[j-1]){
left = i + 1;
}else if(i > 0 && j < len2 && nums1[i-1] > nums2[j]){
right = i - 1;
}else{
//根据奇偶情况输出元素
int maxleft;
//移动到边界
if(i == 0){
maxleft = nums2[j - 1];
}else if(j == 0){
maxleft = nums1[i - 1];
}else{
//找到分界位置,判断左边最大元素
maxleft = (nums1[i - 1] > nums2[j - 1] ? nums1[i - 1]:nums2[j - 1]);
}
//奇数和输出单个元素
if((len1 + len2)%2) return maxleft;
//偶数和找到最小右元素
int minright;
if(i == len1){
minright = nums2[j];
}else if(j == len2){
minright = nums1[i];
}else{
minright = (nums1[i] < nums2[j]) ? nums1[i]:nums2[j];
}
return (maxleft + minright)/2.0;
}
}
return 0.0;
}
};
#python
#方法一:暴力求解
class Solution:
def findMedianSortedArrays(self, nums1: List[int], nums2: List[int]) -> float:
lst = []
i = j = 0
while (i < len(nums1)) and (j < len(nums2)):
if (nums1[i] > nums2[j]):
lst.append(nums2[j])
j += 1
else:
lst.append(nums1[i])
i += 1
if i < len(nums1):
lst.extend(nums1[i:])
else:
lst.extend(nums2[j:])
return (lst[int(len(lst)/2)] + lst[int((len(lst) - 1)/2)])/2
'''也可直接通过sorted函数直接合并两列表并排序'''
#方法二:数组遍历
class Solution:
def findMedianSortedArrays(self, nums1: List[int], nums2: List[int]) -> float:
left = right = 0
i = j = k = 0
alen = len(nums1) + len(nums2)
while k <= alen/2:
left = right
if i < len(nums1) and (j >= len(nums2) or (nums1[i] < nums2[j])):
right = nums1[i]
i += 1
else:
right = nums2[j]
j += 1
k += 1
if alen%2:
return right
else:
return (left + right)/2.0
#方法三:第k小数
def findMedianSortedArrays(nums1, nums2):
len1 = len(nums1)
len2 = len(nums2)
left = int((len1 + len2 + 1) / 2)
right = int((len1 + len2 + 2) / 2)
return (getKth(nums1, nums2, left) + getKth(nums1, nums2, right)) / 2.0
def getKth(num1, num2, k):
if len(num1) > len(num2): return getKth(num2, num1, k)
if len(num1) == 0: return num2[k - 1]
if k == 1: return min(num1[0], num2[0])
i = int(min(len(num1), k/2)) - 1
j = int(min(len(num2), k/2)) - 1
if num1[i] <= num2[j]:
if i + 1 < len(num1): return getKth(num1[i+1:], num2, k - i - 1)
else: return getKth([], num2 ,k -i -1)
else:
return getKth(num1, num2[j+1:], k - j - 1)
#方法四:分割思想
class Solution:
def findMedianSortedArrays(self, nums1: List[int], nums2: List[int]) -> float:
len1 = len(nums1)
len2 = len(nums2)
slen = len1 + len2
if len1 > len2: return self.findMedianSortedArrays(nums2,nums1)
left = 0
right = len1
while left <= right:
i = int((left + right)/2)
j = int((len1 + len2 + 1)/2) - i
maxleft = minright = 0
if i < len1 and j > 0 and nums1[i] < nums2[j-1]:
left = i + 1
elif i > 0 and j < len2 and nums1[i-1] > nums2[j]:
right = i - 1
else:
if i == 0:
maxleft = nums2[j - 1]
elif j == 0:
maxleft = nums1[i - 1]
else:
maxleft = max(nums1[i - 1], nums2[j - 1])
if slen%2:
return maxleft
else:
if i == len1:minright = nums2[j]
elif j == len2:minright = nums1[i]
else:
minright = min(nums1[i], nums2[j])
return (left + minright)/2
return 0.0
后续除非有python的简易实现,否则不给出Python代码