python
一. 无脑傻瓜版本:
没看答案
1.把两个数组合并成一个数组并排序;
2.找到新数组的中位数。
class Solution:
def findMedianSortedArrays(self, nums1, nums2):
ls = list()
for i in nums1:
ls.append(i)
for j in nums2:
ls.append(j)
ls.sort()
num = len(ls)
a = 0
if num % 2 == 0:
a = (ls[num//2-1] + ls[num//2])/2
else:
a = ls[num//2]
return a
复杂度分析:
- 时间复杂度和空间复杂度都是O(m+n)。
二. 二分查找:
主要思路:
-
要找到第 k (k>1) 小的元素,那么就取 prior1 = nums1[k//2-1] 和 prior2 = nums2[k//2-1] 进行比较;
-
nums1 中小于等于 prior1 的元素有 nums1[0 … k//2-2] 共计 k//2-1 个,nums2 中小于等于 prior2 的元素有 nums2[0 … k//2-2] 共计 k//2-1 个;
-
取 prior = min(prior1, prior2),两个数组中小于等于 prior 的元素共计不会超过 (k//2-1) + (k//2-1) ≤ k-2 个,这样 prior 本身最大也只能是第 k-1 小的元素(即prior1=prior2的时候);
-
如果 prior = prior1,那么 nums1[0 … k//2-1] 都不可能是第 k 小的元素。把这些元素全部"删除",剩下的作为新的 nums1 数组(即指针移动到k//2位置),如果 prior= prior2,那么 nums2[0 … k//2-1] 都不可能是第 k 小的元素,把这些元素全部 “删除”,剩下的作为新的 nums2 数组(即指针移动到k//2位置);
-
由于我们 “删除” 了一些元素(这些元素都比第 k 小的元素要小),因此需要修改 k 的值,减去删除元素的个数。
class Solution:
def findMedianSortedArrays(self, nums1, nums2):
m, n = len(nums1), len(nums2)
def getKthitem(k):
index0, index1 = 0, 0 # nums1 和 nums2 的指针位置
while True:
if index0 == m:
return nums2[index1 + k - 1]
if index1 == n:
return nums1[index0 + k - 1]
if k == 1:
return min(nums1[index0], nums2[index1])
newindex0 = min(index0 + k//2 - 1, m-1) # 二分查找,且防止越界
newindex1 = min(index1 + k//2 - 1, n-1) # 二分查找,且防止越界
prior1, prior2 = nums1[newindex0], nums2[newindex1]
if prior1 <= prior2: # 一次只对一个数组进行操作
k -= newindex0 - index0 + 1 # k减去删除元素的个数
index0 = newindex0 + 1 # “删除”元素
else:
k -= newindex1 - index1 + 1 # k减去删除元素的个数
index1 = newindex1 + 1 # “删除”元素
totallength = m + n
if totallength % 2 == 0:
return (getKthitem(totallength//2) + getKthitem(totallength//2+1))/2
else:
return getKthitem(totallength//2+1)
复杂度分析:
- 时间复杂度:O(log(m+n)),其中 m 和 n 分别是数组 nums1 和 nums2 的长度。
- 空间复杂度:O(1)。
c++
class Solution {
public:
double findMedianSortedArrays(vector<int>& nums1, vector<int>& nums2) {
// 可以将该问题转化为找出nums1+nums2的第k小的数
// 由于要求对数时间复杂度,故考虑用二分查找思想,需要考虑如何在每次搜索后,都能排除一半的搜索空间
// 考虑设定标定值为a=nums1[k/2-1]和b=nums2[k/2-1]:
// 如果a小于等于b,则不大于a的数最多只有k/2-1 + k/2-1 = k-2个,算上a本身也最多是第k-1小的数,所以nums1[0:k/2-1]都可以排除了
// 如果a大于b,同理可以排除nums2[0:k/2-1]
// 每次排除后,k要减去排除的数字个数k/2,实现k的更新
// 最终当k为1时,返回此时nums1和nums2剩余部分的最左侧元素中小的那个
// 如果排除过程中某个数组无剩余了,则返回另一个数组剩余部分的此时第k个元素
int length = nums1.size() + nums2.size();
if (length % 2 == 1) {
return get_kth_element(nums1, nums2, length / 2 + 1);
} else {
return (get_kth_element(nums1, nums2, length / 2) + get_kth_element(nums1, nums2, length / 2 + 1)) / 2.0;
}
}
double get_kth_element(vector<int> nums1, vector<int> nums2, int k) {
int m = nums1.size(), n = nums2.size();
// 两个数组每次设置标定值的起点索引,以此来模拟排除元素
int index1 = 0, index2 = 0;
while (true) {
if(index1 == m) {
return nums2[index2 + k - 1];
}
if (index2 == n) {
return nums1[index1 + k - 1];
}
if (k == 1) {
return min(nums1[index1], nums2[index2]);
}
int curr_index1 = min(index1 + k/2-1, m-1);
int curr_index2 = min(index2 + k/2-1, n-1);
// k必须通过两个索引的差值进行更新,因为可能某个数组非常短,排除的元素可能小于k/2个
if (nums1[curr_index1] <= nums2[curr_index2]) {
k -= curr_index1 - index1 + 1;
index1 = curr_index1 + 1;
} else {
k -= curr_index2 - index2 + 1;
index2 = curr_index2 + 1;
}
}
}
};