[算法 LeetCode_004] Median of Two Sorted Arrays

题目描述

There are two sorted arrays nums1 and nums2 of size m and n respectively.
Find the median of the two sorted arrays. The overall run time complexity should be O(log(m+n)) O ( log ⁡ ( m + n ) ) .

Example 1:

nums1 = [1, 3]
nums2 = [2]
The median is 2.0

Example 2:

nums1 = [1, 2]
nums2 = [3, 4]
The median is (2 + 3)/2 = 2.5

算法思路

本题是求两个有序数组的中位数,最简单的想法是用两个指针遍历数组,每次寻找两个数组的最小值,总遍历 (m+n)/2 ( m + n ) / 2 次后便可以找到中位数,时间复杂度为 O(m+n) O ( m + n )

题目要求时间复杂度为 O(log(m+n)) O ( log ⁡ ( m + n ) ) ,所以要思考更高效的算法。

首先思考中位数的本质,对于一系列有序数字,中位数 mid 所在的位置可以将有序数列分割为长度相等的两部分 l_partr_part,即有 len(l_part) == len(r_part),并且满足两部分中的所有数字满足 max(l_part) <= min(r_part)

对于两个有序数组 nums1nums2,长度分别为 mn,算法的思路是在 nums1 中找到位置 i 上的元素,在 nums2 中找位置 j = (m+n)/2-i 上的元素,这样便可满足 (i+j) == (m+n)/2,可将两数组分为长度相等的两部分。
其中 nums1[i]nums2[j] 为后半部分的最小的两个元素,(i+j) 为前半部分的长度,nums1[i-1]nums2[j-1] 为前半部分的最大的两个元素。那么中位数需要同时满足:

nums1[i-1] <= nums2[j]nums2[j-1] <= nums1[i]

注意应该满足 m <= n,如此当 i >= 0 && i <= m 时,可保证 j = (m+n)/2-i 中的 j <= n && j >= 0。如果同时 n == 0,则表示两个数组都没有元素,这不是正常数据。

当某个 ij 不能同时满足 nums1[i-1] <= nums2[j]nums2[j-1] <= nums1[i] 时,需要考虑如何修正 i 的值。

查找 i 使用二分查找,start,end = 0,m (start,end] ( s t a r t , e n d ] ),i = (start+end)/2,当 start <= end 时:
如果 nums1[i-1] > nums2[j],那么需要减小 nums1[i-1] 的值,nums2[j] 的值也会随之增大,所以修正方法是 end = i-1,满足条件的 i 在前 i-1 部分。
如果 nums2[j-1] > nums1[i],那么需要增大 nums1[i] 的值,nums2[j-1] 的值也会随之减小,所以修正方法是 start = i+1,满足条件的 i 在后 end-(i+1) 部分。

当找到满足条件的 ij 之后,因为 (i+j) == (m+n)/2
如果 (m+n)%2 == 1,则中位数为

r = min(nums1[i],nums2[j]);
mid = r;

如果 (m+n)%2 == 0,则中位数应该时

l = max(nums1[i-1],nums2[j-1]);
r = min(nums1[i],nums2[j]);
mid = (l+r)/2;

现在需要考虑边界条件,即 i == 0i == mj == 0j == n
因为有 j = (m+n)/2-i 的约束条件,所以当 i > 0 必有 j < n,当 i < m 必有 j > 0 。故可在查找 i 的判断过程中添加相应的约束条件:

while(start<=end){
    if(i>0 && nums1[i-1]>nums2[j])
        end = i-1;
    else if(i<m && nums[j-1]>nums[i])
        start = i+1;
    else break;
}

找到满足条件的 ij 之后,对于求 r 时:

// 不可能同时有 i == m && j == n
if(i == m) r = nums2[j];
else if(j == n) r = nums1[i];
else r = min(nums1[i],nums2[j]);

if((m+n)%2 == 1) return r;

对于求 l 时:

//不可能同时有 i == 0 && j == 0
if(i == 0) l = nums2[j-1];
else if(j == 0) l = nums1[i-1];
else l = max(nums1[i-1],nums2[j-1]);

return (l+r)/2.0;

这样便能够求得最终结果,算法复杂度为 O(logmin(m,n)) O ( log ⁡ m i n ( m , n ) )

参考资料

[1] https://leetcode.com/problems/median-of-two-sorted-arrays/discuss/2481/Share-my-O(log(min(mn))-solution-with-explanation

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值