欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

【LeetCode】median of two sorted arrays(两个有序数组的中值)

程序员文章站 2022-05-14 20:19:33
...

题目

There are two sorted arrays A and B 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)).
有两个排序的数组A和B分别是m和n。找到两个排序数组的中值。总的运行时间复杂度应该是O(log(m+n))。

思路一:

//合并数组,然后快速确定中间值

  • (1)第一步将两个有序数组合并成一个有序的数组(或者向量)(类似于两个有序链表的合并)
  • (2)得到最终的数组(或者向量)长度为m+n,然后判断是有奇数个值,还是有偶数个值
  • (3)如果有奇数个值,那么只有一个中间值,对应的编号为 (数组(或者向量)长度 -1)/2,取出值,直接返回
  • (4)如果有偶数个值,那么有两个中间值,对应编号为:
    1)数组(或者向量)长度 /2
    2)数组(或者向量)长度 /2 - 1
  • (5)取出对应的值,然后求平均,得到最终结果 */

参考代码

class Solution {
public:
    double findMedianSortedArrays(int A[], int m, int B[], int n) {
        int C[m+n];
        memset(C,0,(m+n)*sizeof(int));
        int k=0;
        int i=0,j=0;//定义下标,其中i是向量1的下标,j是向量2的下标
        while(i<m&&j<n)
        {

            if(A[i]<=B[j])
                C[k++]=A[i++];
            else
                C[k++]=B[j++];

        }
         //数组B还有剩余部分,将数组B剩余部分依次插入
        if(i==m)
        {
            while(j<n)
                C[k++]=B[j++];
        }   
        else if(j==n)//数组A还有剩余部分,将数组A剩余部分依次插入
        {
            while(i<m)
                C[k++]=A[i++];
        }
        if((m+n)&1)//有奇数个值(一个中间值)
            return C[(m+n)>>1]*1.0;
        else////有偶数个值(两个中间值,求平均值)
            return (C[(m+n)>>1]+C[((m+n)>>1)-1])*0.5;   ////-号优先级比>>高
    }
};

思路二:(最优解)


  • 这道题更通用的形式,就是找到两者所有元素中的第k小的元素。
  • O(m+n)的解法比较直观,直接merge两个数组,然后求第k大值。
  • 不过我们仅仅需要的是找第k大值,是不需要“排序”这莫昂贵的操作的。可以用一个计数器,记录当前已经找到第m大的元素了,同时使用两个指针pa,pb,分别指向A、B两个数组的第一个元素,类似于merge sort(归并排序)的原理,如果A当前元素小则pa++;同时m++;如果B当前元素小,那么pb++;同时m++;最终当m==k,就得到答案了,O(k)的空间,O(1)的空间,但是当k接近m+n时,时间还是O(m+n)的。
  • 还没有更好思路呢?我们换种思路,我们可以从k入手,如果每次都能删除一个一定在第k大元素之前的元素呢,此时,,我们需要进行k次,如果每次删一半呢?由于A、B都是有序,我们可以类似于二分查找,也利用了有序。
  • 假设两个数组个数都是大于k/2,我们将A的第k/2(即A[k/2-1])和B的第k/2个元素(即B[k/2-1])进行比较,有如下三种情况(为了此处方便设k为偶数,即共奇数个数,所得结论通用的):

  • A[K/2-1] == B[K/2-1]
  • A[K/2-1] > B[K/2-1]
  • A[K/2-1] < B[K/2-1]
  • 如果第二种情况,就意味着A[K/2-1]不可能大于AUB的第k大元素。
  • 因此,可以删除A组中k/2数据了,同理,可以删除B组中k/2数据。
    当A[k/2-1]=B[k/2-1]时,说明找到了第k大的元素,直接返回A[k/2-1]或B[k/2-1]即可。
    因此,我们可以写一个递归函数。那么函数什么时候终止呢?
    (1)当A或B是空时,直接返回A[k-1]或B[k-1]
    (2)当k=1时,返回min(A[0],B[0])
    (3)当A[k/2-1] == B[k/2-1]时,返回A[k/2-1]或B[k/2-1]

参考代码

class Solution {
public:
    double findMedianSortedArrays(int A[], int m, int B[], int n) {
        int total = m+n;
        if(total & 1)
            return findkth(A,m,B,n,total/2+1);
        else
            return (findkth(A,m,B,n,total/2)+findkth(A,m,B,n,total/2+1))/2;
    }

    double findkth(int A[], int m, int B[], int n, int k)
    {
        if(m>n)
            return findkth(B,n,A,m,k);
        if(m==0)
            return B[k-1];
        if(k==1)
            return min(A[0],B[0]);
        int midA = min(k/2,m);
        int midB = k-midA;
        if(A[midA-1]<B[midB-1])
        {
            return findkth(A+midA,m-midA,B,n,k-midA);
        }
        else if(A[midA-1]>B[midB-1])
        {
            return findkth(A,m,B+midB,n-midB,k-midB);
        }
        else//A[midA-1]==B[midB-1]
            return A[midA-1];
    }
};

结语

夜的寂静,只为迎接绚丽的日出