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 ] ;
    }
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章