Leetcode4: Median of Two Sorted Arrays (求已排序两个数组的中间值)

最开始的想法是利用归并排序的归并merge函数将数组先完全排序,然后根据奇偶个数来决定中间值的大小,思路清晰,代码简单,如下:
<pre name="code" class="java">public class Solution {
    public double findMedianSortedArrays(int A[], int B[]) {
        int m = A.length;
        int n = B.length;
        int[] temp = new int[m+n];
        int idx_a = 0;
        int idx_b = 0;
        int idx = 0;
        while (idx_a < m && idx_b < n) {
            if (A[idx_a] < B[idx_b]) {
                temp[idx++] = A[idx_a++];
            } else {
                temp[idx++] = B[idx_b++];
            }
        }
        
        while (idx_a < m) {
            temp[idx++] = A[idx_a++];
        } 
        
        while (idx_b < n) {
            temp[idx++] = B[idx_b++];
        }
        
        int medium = (m+n)>>1;
        return (double) (m+n) % 2 == 0 ? (temp[medium] + temp[medium - 1])/2.0 : temp[medium];
    }
}


 
编译能够通过,但是好像不符合题目对时间复杂度的要求,该算法时间复杂度为O(n+m)。

在网上看到一种符合的算法,利用类似二分法的思想,先求合并集合A和B的第K大的元素,然后利用该小函数来求解中间值的问题:
对已排好序的两个数组,查找第k大元素,只需要每次比较每个数组前k/2个元素的大小,就可以排除k/2个干扰元素,从排除后的元素开始,继续寻找第k-l大的元素,l为已经被排除的元素个数,利用递归调用,直到找到第K大元素为止;关键是考虑递归结束的边界条件,和每次排除元素后调用函数传入参数的值,下面是代码:
<pre name="code" class="java">import java.util.*;

public class Solution {
    public double findMedianSortedArrays(int A[], int B[]) {
        int m = A.length;
        int n = B.length;
        int total = m + n;
        int k = (total+1) / 2;//第k大元素在数组中序列号为k-1,很关键
        return total % 2 == 0 ? (find_kth_elm(A, m, B, n, k) + find_kth_elm(A, m, B, n, k+1))/2.0 :
                                find_kth_elm(A, m, B, n, k);
    }
    
    /**
     * 对已排序的两个数组查找第k大的元素
     */
    public int find_kth_elm(int a[], int m, int b[], int n, int k) {
    //we always assume that m equal or less than n
    if (m > n) {
        return find_kth_elm(b, n, a, m, k);
    }
    
    //递归结束的边界条件
    if (m == 0) {
        return b[k-1];
    } 
    
    if (k == 1) {
        return a[0] < b[0] ? a[0] : b[0];
    }
    
    //每次搜索,将k/2个元素排除,递归寻找目标元素
    int ma = (k/2 < m ? k/2 : m);
    int nb = k - ma;
    if (a[ma-1] > b[nb-1]) {
        //则此时b[0:nb-1]必然是小于第k大的值,可以删除,从nb以后的元素中搜索,目标是A和B集合中第k-nb大的元素
        return find_kth_elm(a, m, Arrays.copyOfRange(b, nb, n), n-nb, k-nb);
    } else if (a[ma-1] < b[nb-1]) {
        //则此时a[0:ma-1]必然是小于第k大的值,可以删除,从nb以后的元素中搜索,目标是A和B集合中第k-nb大的元素
        return find_kth_elm(Arrays.copyOfRange(a, ma, m), m-ma, b, n, k-ma);
    } else {
        //a[ma-1]=b[nb-1],则此时第K大元素必然是该相等元素
        return a[ma-1];
    }
    
    }

}


 



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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值