Median of Two Sorted Arrays(2)

Median of Two Sorted Arrays(2)

哎,自己真是个意志薄弱的人,一隔就是几个月的时间没有更新,原因也不过是因为这道题卡住了,对于算法方面的知识,自己深知还需要锻炼啊。废话少说,开始分析自己的原因吧,骚年。

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)).

上面贴出原文,上次我用快速排序的方法提交后,发现也可以accept。但是心里总是别扭,想着能够思考出来O(log(m+n)),但是我发现自己真的是需要锻炼,加起来思考了有一个星期,居然没有一点思路,这还是在已经得到提示的情况下,二分法可以做,但是想想可能也就是因为这个提示限制了我的思路。不得已,我浏览了一些大神的解法,立刻豁然开朗,自己真的是死心眼啊。
之前的思路我一直在想既然是二分法,就一定与两个数组各自的中位数有关系,于是就想着比较两个中位数,然后减少一些数量,表面上一看,这个方法行得通,我还尝试了编码。。。。。结果肯定是不能通过,再来检查一下就会发现,我比较两个中位数a、i, b、j,其中a,b为具体数,ij为位置,如果a < b,那么把i以前的数都去掉,j以后的数都去掉,自己觉得还挺对,结果呢,去掉后再迭代就找不到原来的中位数了,原因是为啥,因为中位数两边去掉的数量不相等。这下这个思路是彻底被否决了,然后,呵呵,我就无计可施了。。。
再来看看这次我理解的解法。这个问题还可以再延伸一下,改编成下面的问题

在两个已经排序好的数组中找到第k大的数字

这是个很解放思想的一个方法,如果是找到中位数的话,那我们就要一直考虑奇偶数,因为奇偶数时,中位数的计算方法不一样,所以这一步很关键,也很巧妙,让问题变的更普通化,既让问题好解决了,也能解决更加普遍性的问题。
在discuss里面看了一些代码和解释后,我能明白这个算法的逻辑了,但是我一直想找出这个问题的初始的思想,也就是说是看到这个问题之后是怎么想到这个解决办法的。应该怎么对待一个这样的问题,然后设计出算法来解决。我觉得首先是因为两个排序好的数组,所以肯定会想到二分查找的方法,因为二分查找的方法也是O(lgn),所以基本可以确定是二分查找,但是怎么二分法,肯定跟正常的不一样了,需要有些变换,但是思想是不会变的。下面说一下我的理解。
如果两个数组合并成一个,那么找出第k大的来就是再简单不过的事情了。假设两个数组已经排序好合并成一个数组

a[i1],b[j1],a[i2],a[i3],b[j2],…

其中第k个数以及以前的数包含这几种情况:

  • 全是数组a中的
  • 全是数组b中的
  • 数组a和b混合的
    第一种情况用语言来表达是a[k] < b[0]
    第二种情况用语言来表达是b[k] < a[0]
    第三种情况是混合的,但无非就是两种情况
  • a中的数多一些
  • b中的数多一些

这里面还有一个特殊的情况,那就是前k个数中,属于a和b的数各占一半,其他的情况其实就是处在它们之间的一个过渡状态,为什么说过渡呢,因为如果a中的数多一些,那么b中的数必然会相应少一些;如果第k个数是a[k/2],那么如果前k个数a数组中的多一些,那么第k个数就是在a{k/2~n1}和b{0~k/2-1}中选了,这时候就可以去掉一半的数了,那就是a{0~k/2-1}和b{k/2~n2}。那么关键就是怎么确定前k个数中,到底是a多一些,还是b多一些。可以得出两个不等式
下面对应第k个数是a中的

b[k/2] >= a[k/2+m] >= bk/2-m
a[k/2] >= a[k/2-m] >= bk/2+m

如果是b中的数呢,那么就是

a[k/2] >= b[k/2+m] >= ak/2-m
b[k/2] >= b[k/2-m] >= ak/2+m

其中m的取值是

0 =< m <= k/2

从上面的不等式中可以总结出两种情况,不管是第k个数是a中的,还是b中的

b[k/2]>=ak/2+m
a[k/2]>=bk/2+m

由于m对于任何0都是成立的,所以就转换成了

b[k/2]>=ak/2
a[k/2]>=bk/2

所以,二分法的基本逻辑就可以写出来了,当知道是a中多一些的时,可以相应去掉a{0~k/2-1}和b{k/2~n2},反过来也是如此。(终于想通了!!!)
上面还有一种情况没有考虑到,那就是有可能a的数组或者b的数组的个数没有k/2个,那么情况就不能像上面那样简单的考虑去掉a{0~k/2-1}和b{k/2~n2},这时候可能考虑,b[k/2] >= a[n1]或者a[k/2] >= b[n2],但是这样一来第k个数就可能落在b{k/2~n2}或者说是a{k/2~n1}里面,因为n1+k/2 <= k或者 n2 + k/2<= k,所以这样的情况就是要减少a{0~n1}或者b{0~n2}

double findkth(int *nums1, int nums1Size, int *nums2, int nums2Size, int k){
    if (nums1Size > nums2Size)
        return findkth(nums2, nums2Size, nums1, nums1Size, k);
    if (nums1Size <= 0)
        return (double)nums2[k-1];
    if (k == 1)
        if (nums1[0] > nums2[0])
            return nums2[0];
        else
            return nums1[0];

    int l = nums1Size < k/2 ? nums1Size : k/2;
    int r = k/2;

    if (nums1[l-1] <= nums2[r-1])
        return findkth(nums1+l, nums1Size-l, nums2, nums2Size, k-l);
    if (nums1[l-1] > nums2[r-1])
        return findkth(nums1, nums1Size, nums2+r, nums2Size-r, k-r);
}
double findMedianSortedArrays(int* nums1, int nums1Size, int* nums2, int nums2Size) {
    if ((nums1Size+nums2Size)%2==0)
        return (findkth(nums1, nums1Size, nums2, nums2Size, (nums1Size+nums2Size)/2) + findkth(nums1, nums1Size, nums2, nums2Size, (nums1Size+nums2Size)/2+1))/2;
    else
        return findkth(nums1, nums1Size, nums2, nums2Size, (nums1Size+nums2Size)/2+1);
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值