leetcode題目4.尋找兩個有序數組的中位數(困難)


題目描述:

給定兩個大小為 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

解法一:雖然不符合時間復雜度要求,但是為了說明一下思路,還是cover一下,本地調試和提交都通過了,貌似leetcode缺少復雜度分析機制。

思路:兩個排好序的數組,將兩個數組合並成一個有序數組,若大數組的長度為奇數,則中位數為大數組中間的那個數,否則中位數為索引值分別是(0+arr.length)和(0+arr.length+1)之和的平均值

class Solution {
    
    public double findMedianSortedArrays(int[] nums1, int[] nums2) {
        
        int m = nums1.length;
        int n = nums2.length;
        return getMedian(nums1,m,nums2,n);
        
    }
    
    private  double getMedian(int[] nums1, int m, int[] nums2, int n) {

        int i = 0;
        int j = 0;
        int k = 0;
        int[] resultArr = new int[m + n];
        while (i < m && j < n) {
            if (nums1[i] <= nums2[j]) {
                resultArr[k++] = nums1[i++];
            } else {
                resultArr[k++] = nums2[j++];
            }
        }
        while (i < m) {
            resultArr[k++] = nums1[i++];
        }
        while (j < n) {
            resultArr[k++] = nums2[j++];
        }
        int rn = k-1;
        if (rn % 2 == 0) {
            return resultArr[rn / 2] * 1.0 ;
        } else {
            return (resultArr[rn / 2] + resultArr[rn / 2 + 1]) * 1.0 / 2;
        }
    }
}

復雜度分析:

~時間復雜度:O(m+n)

~空間復雜度:O(m+n)

解法二:遞歸

思路:

       兩個有序數組求中位數,問題一般化為,求兩個有序數組的第k個數,當k = (m+n)/2時為原問題的解。怎么求第k個數?分別求出第一個和第二個數組的第 k / 2個數 a 和 b,然后比較 a 和 b,當a < b ,說明第 k 個數位於 a數組的第 k / 2個數后半段,或者b數組的 第 k / 2 個數前半段,問題規模縮小了一半,然后遞歸處理就行。

class Solution {
    public double findMedianSortedArrays(int[] nums1, int[] nums2) {
        
        int m = nums1.length;
        int n = nums2.length;
        
          //當nums1數組為空的時候
        if (m == 0) {
            //兩個數組的中位數完全取決於數組nums2了
            if (n % 2 == 1) {
                return nums2[n / 2] * 1.0;
            }
            return (nums2[n / 2] + nums2[n / 2 -1]) / 2.0;
        }

        //當nums2數組為空的時候
        if (n == 0) {
            if (m % 2 == 1) {
                return nums1[m / 2] * 1.0;
            }
            return (nums1[m / 2] + nums1[m / 2 - 1]) / 2.0;
        }

        //大數組的總長度m+n
        int total = m + n;
        //數組長度為奇數,則在數組中尋找第total/2+1個數
        if (total % 2 == 1) {
            return find_kth(nums1, 0, nums2, 0, total / 2 + 1);
        }
        return (find_kth(nums1, 0, nums2, 0, total / 2) + find_kth(nums1, 0, nums2, 0, total / 2 + 1)) / 2.0;
    }

    private static double find_kth(int[] nums1, int a_begin, int[] nums2, int b_begin, int k) {

        //當a_begin或b_begin超過數組長度,則第k個數為另外一個數組第k個數
        if (a_begin >= nums1.length) {
            return nums2[b_begin + k - 1];
        }
        //同理
        if (b_begin >= nums2.length) {
            return nums1[a_begin + k - 1];
        }
        //遞歸結束條件,每個數組中都找其第一個元素,使用遞歸,必須聲明遞歸結束條件
        if (k == 1) {
            return Math.min(nums1[a_begin], nums2[b_begin]);
        }

        //定義mid_a和mid_b分別代表兩個數組中的第k/2個數

        int mid_a = Integer.MAX_VALUE;
        int mid_b = Integer.MAX_VALUE;

        if (a_begin + k / 2 - 1 < nums1.length) {
            mid_a = nums1[a_begin + k / 2 - 1];
        }

        if (b_begin + k / 2 - 1 < nums2.length) {
            mid_b = nums2[b_begin + k / 2 - 1];
        }
        //如果nums1數組的第 k / 2 個數小於nums2數組的第 k / 2 個數,表示總的第 k 個數位於 nums1的第k / 2個數的后半
        // 段,或者是nums2的第 k / 2個數的前半段,由於范圍縮小了 k / 2 個數,此時總的第 k 個數實際上等於新的范圍內\
        // 的第k - k / 2個數,依次遞歸
        if (mid_a < mid_b) {
            return find_kth(nums1, a_begin + k / 2, nums2, b_begin, k - k / 2);
        }
        return find_kth(nums1, a_begin, nums2, b_begin + k / 2, k - k / 2);
    }
        
}

復雜度分析:
~時間復雜度: O(log(m+n))


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM