Median of Two Sorted Arrays

Median of Two Sorted Arrays

计算机中的算法到底研究的是技巧还是一种思维方式。

分析算法已知条件如下:
- 两个有序数组
- 中位数:奇数取中间值偶数取中间两个数的平均数(浮点型)


直接思路

public class Solution {
    public double findMedianSortedArrays(int[] nums1, int[] nums2) {
    int length=nums1.length+nums2.length;
        boolean odd=length%2==1;
        int index=0;
        if(odd){
            index=length/2;
        }else{
            index=length/2-1;
        }
        System.out.print(index);
        return intAtIndex(nums1,nums2,index,odd);

    }

    public double intAtIndex(int[] nums1,int[] nums2,int index,boolean odd){
        int temp=0;
        int left=0;
        int right=0;
        double result=0;
        while(temp<index){
            if(left<nums1.length&&right<nums2.length&&nums1[left]<nums2[right]){
                left++;
            }else if(left==nums1.length){
                right++;
            }else if(right==nums2.length){
                left++;
            }else{
                right++;
            }
            temp++;
        }
        if(odd){
            if(left==nums1.length){
                result=nums2[right];
            }else if(right==nums2.length){
                result=nums1[left];
            }else{
                result=nums1[left]<nums2[right]?nums1[left]:nums2[right];
            }

        }else{
            String temp1=findNext(nums1,nums2,left,right);
            String[] temps=temp1.split(",");
            Integer leftNumber=Integer.parseInt(temps[0]);
            String temp2=findNext(nums1,nums2,Integer.parseInt(temps[1]),Integer.parseInt(temps[2]));
            Integer rightNumber=Integer.parseInt(temp2.split(",")[0]);
            result=(leftNumber+rightNumber)/2.0;
        }

        return result;

    }

    private String findNext(int[] nums1,int[] nums2,int left,int right){
        int result=0;
        if(left==nums1.length){
            result= nums2[right];
            right++;
        }
        else if(right==nums2.length){
            result= nums1[left];
            left++;
        }else if(nums1[left]<nums2[right]){
            result=nums1[left];
            left++;
        }else{
            result= nums2[right];
            right++;
        }
        return result+","+left+","+right;
    }

}

报错:运行时间超时。在本程序中已经尽量只遍历对数组只遍历一次,能优化的点只有第三个函数。

本以为时间复杂度为O(n)的算法已经接近极致了,没想到其实对有序数列来说O(logN),O(1)都是可以优化的目标。到网上翻了一些算法解决方案,主要思路如下:

  • 将找中位数抽象为找第k小的数,既然已经告知两个数组有序,那就要充分利用此有效信息,减少算法的遍历范围。缩小范围从二分法开始:两边同时二分法,A[k/2]与B[k/2]进行比较,较小者的前半段可以不再比较,以此类推,逐渐跳跃式的减少对搜索空间的遍历。

    看到我的第三个函数我只想说业务代码写多了,脑子里都是渣呀。优化后的算法如下:

public class Solution {
    public double findMedianSortedArrays(int A[], int B[]) {
        int len = A.length + B.length;
        if (len % 2 == 1) {
            return findKth(A, 0, B, 0, len / 2 + 1);
        }
        return (
            findKth(A, 0, B, 0, len / 2) + findKth(A, 0, B, 0, len / 2 + 1)
        ) / 2.0;
    }

    // find kth number of two sorted array
    public static int findKth(int[] A, int A_start,
                              int[] B, int B_start,
                              int k){       
        if (A_start >= A.length) {
            return B[B_start + k - 1];
        }
        if (B_start >= B.length) {
            return A[A_start + k - 1];
        }

        if (k == 1) {
            return Math.min(A[A_start], B[B_start]);
        }

        int A_key = A_start + k / 2 - 1 < A.length
                    ? A[A_start + k / 2 - 1]
                    : Integer.MAX_VALUE;
                    //此处为算法的技巧点,
        //本质比较的是第k/2个数,当index越界时,认为其中位数为最大整数,不在此轮进行比较A数组的元素,而是去比较B数组的元素,从而减小K的取值。
        //最大整数的引用,可以规范算法的形式,思想以后可以借鉴
        int B_key = B_start + k / 2 - 1 < B.length
                    ? B[B_start + k / 2 - 1]
                    : Integer.MAX_VALUE; 

        if (A_key < B_key) {
            return findKth(A, A_start + k / 2, B, B_start, k - k / 2);
        } else {
            return findKth(A, A_start, B, B_start + k / 2, k - k / 2);
        }
    }
}

优化算法来源:http://www.jiuzhang.com/solutions/median-of-two-sorted-arrays/

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值