LeetCode-寻找两有序数组中位数

算法描述

给定两个大小为 m 和 n 的有序数组 nums1 和 nums2。

请你找出这两个有序数组的中位数,并且要求算法的时间复杂度为 O(log(m + n))。

你可以假设 nums1 和 nums2 不会同时为空。

示例 1:

nums1 = [1, 3]
nums2 = [2]

则中位数是 2.0

示例 2:

nums1 = [1, 2]
nums2 = [3, 4]

则中位数是 (2 + 3)/2 = 2.5

第一个版本
	public double findMedianSortedArrays(int[] nums1, int[] nums2) {
        // 每次去掉一个最小,一个最大,需要四个下标
        if (null == nums1 || nums1.length == 0) {
            return getNum(nums2);
        }
        if (null == nums2 || nums2.length ==0){
            return getNum(nums1);
        }

        int[] nums = new int[nums1.length + nums2.length];
        // 都不为空
        int indx1 = 0;
        int indx2 = 0;
        int idx = 0;
        // 当全部都还没取完
        while(indx1 != nums1.length  &&  indx2 != nums2.length){
            if (nums1[indx1] > nums2[indx2]){
                // 放小的
                nums[idx++] = (nums2[indx2++]);
            }else{
                nums[idx++] = (nums1[indx1++]);
            }
        }

        if (indx1 != nums1.length){
            //TODO
            for(int i = indx1; i < nums1.length; i++){
                nums[idx++] = nums1[i];
            }
        }
        if (indx2 != nums2.length){
            for(int i = indx2; i < nums2.length; i++){
                nums[idx++] =  nums2[i];
            }
        }

        for (int i = 0; i < idx; i++){
            System.out.println(nums[i]);
        }
        return getNum(nums);
    }

    private double getNum(int[] num){

        return ((num.length) & 1) == 0 ? (double)((num[(num.length >> 1) - 1] + num[num.length >> 1])/2.0) : num[num.length >> 1 ] ;
    }

这个版本浪费了很多空间,可以将空间复杂度降到O(1),也就是优化后的版本。

优化版本
	public double findMedianSortedArrays(int[] nums1, int[] nums2) {
        // 每次去掉一个最小,一个最大,需要四个下标
        if (null == nums1 || nums1.length == 0) {
            return getNum(nums2);
        }
        if (null == nums2 || nums2.length ==0){
            return getNum(nums1);
        }

        // 找下标
        int totalLen = nums1.length + nums2.length;
        boolean isOdd = (totalLen & 1) > 0;
        int theFisrtPosition = ((totalLen + 1) >> 1 ) - 1; // 假设已经排序,这是
        // 都不为空
        int indx1 = 0;
        int indx2 = 0;
        int startIndex = -1; // 指向上一个虚拟数组中的下标
        // 当全部都还没取完
        int tmp = 0;
        while(indx1 < nums1.length  &&  indx2 < nums2.length && startIndex < theFisrtPosition){
            if (nums1[indx1] > nums2[indx2]){
                tmp = nums2[indx2++];
            }else{
                tmp = nums1[indx1++];
            }
            startIndex++;
        }
        // 计数到thefirstIdx,或者存在一个数组用完,找到接下来的两个
        if(startIndex == theFisrtPosition){ // 计数到theFirstIdx
            if (isOdd){ // 奇数
                return tmp;
            }else{
                return (tmp + Math.min(indx1== nums1.length ? Integer.MAX_VALUE : nums1[indx1],
                        indx2 == nums2.length ? Integer.MAX_VALUE : nums2[indx2]))/2.0;
            }
            // 直接就可以return了,找到接下来两个该放的数值
        }else{ // 没有数到,有用完的了
            if(indx1 == nums1.length){ // 在nums2里面
                return isOdd ?  nums2[indx2 + (theFisrtPosition - startIndex - 1)] :
                        (nums2[indx2 + (theFisrtPosition - startIndex - 1)]
                                + nums2[indx2 + (theFisrtPosition - startIndex)])/2.0;// 是奇数,在再另外一个里面计算
            }else{
                return isOdd ? nums1[indx1 + (theFisrtPosition - startIndex - 1)] :
                        (nums1[indx1 + (theFisrtPosition - startIndex - 1)]
                                + nums1[indx1 + (theFisrtPosition - startIndex)])/2.0;// 是奇数,在再另外一个里面计算
            }
        }
  	}

    private double getNum(int[] num){
        return ((num.length) & 1) == 0 ? (double)((num[(num.length >> 1) - 1] + num[num.length >> 1])/2.0) : num[num.length >> 1 ] ;
    }
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章