Java--给定两个有序的数组,长度分别为m和n,求这两个数组中的第K个元素。

Java--给定两个有序的数组,长度分别为m和n,求这两个数组中的第K个元素。

首先想到的是,最普通的算法,比较两个数组,碰到较小的计数器加1,并指向下一个,直到计数等于k。算法复杂度O(m+n);

这是一种会被面试官鄙视的算法。,我也用这个方法,被鄙视过。看完这个方法,在进行优化。

package ppp;

 

public classaa4 {

 

    public static void main(String[] args) {

        int[] aa ={2,5,9,77,88,654,854,999};

        int[] bb ={3,4,6,8,9,12,52,74,68,881,885};

        System.out.println(find(aa,bb,6));

    }

   

    public static int find(int[] aa,int[] bb,int k){

        int num=0,i=0,j=0;

        int[]cc = new int[aa.length+bb.length];

        while(i<aa.length && j<bb.length){

            if(aa[i]<=bb[j]){

                num++;

                i++;

                if(num==k){

                    return aa[i-1];

                }

            }else{

                num++;

                j++;

                if(num==k){

                    return bb[j-1];

                }

            }

        }

        while(i<aa.length && num<k){

            num++;

            i++;

            if(num==k){

                return aa[i-1];

            }

        }

        while(j<bb.length && num<k){

            num++;

            j++;

            if(num==k){

                return bb[j-1];

            }

        }

        return 0;

    }

}

 

 

优化的算法是利用中位数,数组A和B,不妨设aMid<bMid,此时,bMid左侧有aMid+bMid+1个元素,如果k< aMid+bMid+1,则所要寻找的第k个数必在bMid的左边,所以bMid之后的元素不可能出现要找的数,所以可以排除掉B数组的后半部分。

如果k> aMid+bMid+1,则所要寻找的第k个数必在bMid的右边,所以bMid左边的元素不可能出现要找的数,而aMid左半边元素必然出现在bMid的左边,所以可以排除掉A数组左半边的元素。

综上所述,对于 k <= aMid+bMid+1 还是 k > aMid+bMid+1 我们都提出了解决的方案,并且每种方案都能把 A 或者 B 的规模减小一半。减小了一半之后,我们将其作为一个新的问题继续使用上面的算法处理,直到 A 或者 B 减小到足够小: 

1.   A 没有了,这样只需要找出 B 中第 k 大的元素,也就是 B[k]。

2.   B 没有了,同上结果就是 A[k]。

3.  package ppp;

4.  public class aa5 {

5.  private int[] aa;

6.  private int[] bb;

7.  public static void main(String[] args) {

8.       aa5 a = new aa5();

9.       a.aa = newint[] {2,5,9,77,88,654,854,999};

10.      a.bb = newint[] {3,4,6,8,9,12,52,74,68,881,885};

11.      System.out.println(a.find(0,a.aa.length-1,0,a.bb.length-1,7));

12. }

13. public int find(int aLeft,int aRight,int bLeft,int bRight,int k){

14.  

15.      int aMid = (aLeft+aRight)/2;

16.      int bMid = (bLeft+bRight)/2;

17.     

18.      if(aLeft<aRight){

19.          returnbb[bLeft+k-1];

20.      }

21.      if(bLeft<bRight){

22.          returnaa[aLeft+k-1];

23.      }  

24.      if(aa[aMid]<=bb[bMid]){

25.          if(k<=aMid-aLeft+bMid-bLeft+1){

26.              returnfind(aLeft,aRight,bLeft,bMid-1,k);

27.          }else{

28.              returnfind(aMid+1,aRight,bLeft,bRight,k-(aMid-aLeft)-1);

29.          }

30.      }else{

31.          if(k<=aMid-aLeft+bMid-bLeft+1){

32.              returnfind(aLeft,aMid-1,bLeft,bRight,k);

33.          }else{

34.              returnfind(aLeft,aRight,bMid+1,bRight,k-(bMid-bLeft)-1);

35.          }

36.      }

37. }

38. }

 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值