Leetcode 4. 寻找两个正序数组的中位数

Question

ref: https://leetcode.cn/problems/median-of-two-sorted-arrays/
给定两个大小分别为 m 和 n 的正序(从小到大)数组 nums1 和 nums2。请你找出并返回这两个正序数组的 中位数 。

算法的时间复杂度应该为 O ( l o g ( m + n ) ) O(log (m+n)) O(log(m+n))

示例 1:

输入: n u m s 1 = [ 1 , 3 ] , n u m s 2 = [ 2 ] nums1 = [1,3], nums2 = [2] nums1=[1,3],nums2=[2]

输出: 2.00000 2.00000 2.00000

解释:合并数组 = [ 1 , 2 , 3 ] = [1,2,3] =[1,2,3] ,中位数 2 2 2

示例 2 2 2

输入: n u m s 1 = [ 1 , 2 ] , n u m s 2 = [ 3 , 4 ] nums1 = [1,2], nums2 = [3,4] nums1=[1,2],nums2=[3,4]

输出: 2.50000 2.50000 2.50000

解释:合并数组 = [ 1 , 2 , 3 , 4 ] = [1,2,3,4] =[1,2,3,4] ,中位数 ( 2 + 3 ) / 2 = 2.5 (2 + 3) / 2 = 2.5 (2+3)/2=2.5

提示:

n u m s 1. l e n g t h = = m n u m s 2. l e n g t h = = n 0 < = m < = 1000 0 < = n < = 1000 1 < = m + n < = 2000 − 1 0 6 < = n u m s 1 [ i ] , n u m s 2 [ i ] < = 1 0 6 \begin{align*} nums1.length == m \\ nums2.length == n \\ 0 <= m <= 1000 \\ 0 <= n <= 1000 \\ 1 <= m + n <= 2000 \\ -10^6 <= nums1[i], nums2[i] <= 10^6 \\ \end{align*} nums1.length==mnums2.length==n0<=m<=10000<=n<=10001<=m+n<=2000106<=nums1[i],nums2[i]<=106

Answers1

The following code is my answer. but the space complexity is higher than other leet-coder and the rank of the time complexity is around of 25%. We need to further improve the answer quality and make it better.

#include<iostream>
#include<vector>
using namespace std;

double findMedianSortedArrays(vector<int>& nums1, vector<int>& nums2) {
    vector<int> all_num(0);
    int i1 = 0;
    int i2 = 0;
    int pos = 0;
    double result = 0;
    // merge two order list into single order list.
    // using nums1.size() to achieve the length of nums1.

    while (i1 < nums1.size() && i2 < nums2.size())
    {
        if (nums1[i1] <= nums2[i2])
        {
            // append a integer to the end of all_num array
            all_num.push_back(nums1[i1]);
            i1++;
        }
        else
        {
            all_num.push_back(nums2[i2]);
            i2++;
        }
    }

    while(i1 < nums1.size())
    {
        all_num.push_back(nums1[i1]);
        i1++;
    }

    while (i2 < nums2.size())
    {
        all_num.push_back(nums2[i2]);
        i2++;
    }
    
    if ((i1 + i2) % 2 == 0)
    {
        // warning: the result can rounded down(向下取整) with integer division
        pos = (i1 + i2) / 2;
        result = (all_num[pos] + all_num[pos - 1]) / 2.0;
    }
    else
    {
        pos = (i1 + i2) / 2;
        result = all_num[pos];
    }
    
    return result;
}

int main() 
{
    vector<int> nums1 = { 0,1,3 };
    vector<int> nums2 = { 2, 4};
    cout << findMedianSortedArrays(nums1, nums2) << endl;
    return 0;
}

Knowledge Corner

  1. the int type is converted to float or double
int pos = 0;
float pos_f = pos;
\\or
cout << (float) pos << endl;

reference url

Cpp vector https://blog.csdn.net/qiancm/article/details/119611928

Answer 2

The following code don’t need to open more space to save the addition arrays, and just use pointer i and pointer j to solve this problem, the space complexity is converted from O ( m + n ) O(m+n) O(m+n) to O ( 1 ) O(1) O(1).

class Solution {
public:
    double findMedianSortedArrays(vector<int>& nums1, vector<int>& nums2) {
        // 定义 i j 2个指针分别指针2个数组
        // 定义 l r 分别用来保存中位数;奇数个,只会用到 l 变量;偶数,会用到 l r 变量
        int m = nums1.size();
        int n = nums2.size();
        int i = 0, j = 0; 
        int l = 0, r = 0;
        for (int x = 0; x <= (m + n) / 2; x++) {
            l = r;
            r = (i < m && (j >= n || nums1[i] < nums2[j])) ?
                nums1[i++] : nums2[j++];
        }
        return (m + n) & 1 ? r : (l + r) / 2.0;
    }
};

Knowledge Corner

reference url:
bit operator: https://blog.csdn.net/weixin_43736974/article/details/84543970

Answer 3

We further improve the time complexity from O ( m + n ) O(m+n) O(m+n) to O ( l o g ( m + n ) ) O(log(m+n)) O(log(m+n)). The below is solution. The division method is used.

The main thought of the method is the problems is regarded as the question to find the k k k-th biggest element in both arrays. And the pointer i i i and pointer j j j satisfy the following equation.

i + j = k i+j=k i+j=k
n u m s 1 [ i − 1 ] < = n u m s 2 [ j ] & & n u m s 2 [ j − 1 ] < = n u m s 1 [ i ] nums1[i-1]<=nums2[j]\&\&nums2[j-1]<=nums1[i] nums1[i1]<=nums2[j]&&nums2[j1]<=nums1[i]
In the end, the problem becomes m a x ( n u m s 1 [ i − 1 ] , n u m s 2 [ j − 1 ] ) max(nums1[i-1],nums2[j-1]) max(nums1[i1],nums2[j1]).

we just find the proper pointer i using division method, and the pointer j is acquired by equation i + j = k i+j=k i+j=k.

class Solution {
public:
    int findKthElm(vector<int>& nums1,vector<int>& nums2,int k){
        assert(1<=k&&k<=nums1.size()+nums2.size());
        int le=max(0,int(k-nums2.size())),ri=min(k,int(nums1.size()));
        while(le<ri){
            int m=le+(ri-le)/2;
            if(nums2[k-m-1]>nums1[m]) le=m+1;//这为什么只写一个条件?!因为这是二分的排除条件,不是目标的符合条件,相当于排除条件,最后的结果才是符合条件的结果
            else ri=m;
        }//循环结束时的位置le即为所求位置,第k小即为max(nums1[le-1]),nums2[k-le-1]),但是由于le可以为0、k,所以
        //le-1或者k-le-1可能不存在所以下面单独判断下
        int nums1LeftMax=le==0?INT_MIN:nums1[le-1];
        int nums2LeftMax=le==k?INT_MIN:nums2[k-le-1];
        return max(nums1LeftMax,nums2LeftMax);
    }
    double findMedianSortedArrays(vector<int>& nums1, vector<int>& nums2) {
        int n=nums1.size()+nums2.size();
        if(n&1){//两个数组长度和为奇数
            return findKthElm(nums1,nums2,(n>>1)+1);
        }
        else{//为偶数
            return (findKthElm(nums1,nums2,n>>1)+findKthElm(nums1,nums2,(n>>1)+1))/2.0;
        }
    }
};

Reference:

https://leetcode.cn/problems/median-of-two-sorted-arrays/solution/jiang-qi-zhuan-wei-zhao-liang-ge-you-xu-shu-zu-de-/

Other Method

Other methods and some tricks can further improve the Further improve capability of the algorithm. But we don’t note them.

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值