1. 程式人生 > >多陣列中位數,k大數 -- 二分思路

多陣列中位數,k大數 -- 二分思路

多陣列k大數

給定兩個有序陣列arr1和arr2,在給定一個整數k,返回兩個陣列的所有數中第K小的數。
例如:
arr1 = {1,2,3,4,5};
arr2 = {3,4,5};
K = 1;
因為1為所有數中最小的,所以返回1;

arr1 = {1,2,3};
arr2 = {3,4,5,6};
K = 4;
因為3為所有數中第4小的數,所以返回3;

要求:如果arr1的長度為N,arr2的長度為M,時間複雜度請達到O(log(min{M,N}))。

多陣列中位數

給定兩個有序陣列arr1和arr2,兩個陣列長度都為N,求兩個陣列中所有數的上中位數。
例如:
arr1 = {1,2,3,4};
arr2 = {3,4,5,6};
一共8個數則上中位數是第4個數,所以返回3。

arr1 = {0,1,2};
arr2 = {3,4,5};
一共6個數則上中位數是第3個數,所以返回2。

要求:時間複雜度O(logN)

尋找最小的k個數(進一步要求順序與原陣列中元素順序一致)

多陣列k大數 AC程式碼

class Solution {
public:

    int findKthNum(vector<int> arr1, vector<int> arr2, int kth) {
        int len1 = arr1.size();
        int len2 = arr2.size();
        vector
<int>
shortArr = len1 < len2 ? arr1 : arr2; vector<int> longArr = len1 >= len2 ? arr1 : arr2; int lenS = shortArr.size(); int lenL = longArr.size(); if (kth < 1 || kth > len1 + len2) // kth不符合 直接返回 return -1; if (kth <= lenS){ return
getUpMedian(shortArr, 0, kth - 1, longArr, 0, kth - 1); } if (kth > lenL){ if (shortArr[kth - lenL - 1] >= longArr[lenL - 1]){ return shortArr[kth - lenL - 1]; } if (longArr[kth - lenS - 1] >= shortArr[lenS - 1]){ return longArr[kth - lenS - 1]; } return getUpMedian(shortArr, kth - lenL, lenS - 1, longArr, kth - lenS, lenL - 1); } if (longArr[kth - lenS - 1] >= shortArr[lenS - 1]){ return longArr[kth - lenS - 1]; } return getUpMedian(shortArr, 0, lenS - 1, longArr, kth - lenS, kth - 1); } int getUpMedian(vector<int> arr1, int l1,int r1,vector<int> arr2,int l2,int r2) { /* int N1 = arr1.size(); int N2 = arr2.size(); int l1 = 0, r1 = N1 - 1; int l2 = 0, r2 = N2 - 1;*/ while (l1 != r1 || l2 != r2) { int mid1 = (l1 + r1) / 2; int mid2 = (l2 + r2) / 2; // 表示 2分查詢要不要包含中間那個數 奇數是0,偶數是1 int offset = (r1 - l1 + 1) & 1 ^ 1; if (arr1[mid1] > arr2[mid2]) { l2 = mid2 + offset; r1 = mid1; } else if (arr2[mid2] > arr1[mid1]){ l1 = mid1 + offset; r2 = mid2; } else{ return arr1[mid1]; } }// while return arr1[l1] < arr2[l2] ? arr1[l1] : arr2[l2]; } };

注意點:

  • 求中位數 採用了二分思路

  • 求中位數 用二分是 要注意長度為奇偶是不一樣的(middle位置的數要不要取的問題),還要注意最後的處理

  • 在求第k大數時,要分情況,淘汰掉一些顯然不滿足的情況,轉換為求中位數問題,這裡需要對k的大小分類討論,見程式碼.
    下面是其中一種情況的說明
    這裡寫圖片描述

Median of Two Sorted Arrays(leetcode)

ac程式碼, 藉助多陣列k大數

class Solution {
public:

    double findMedianSortedArrays(vector<int>& nums1, vector<int>& nums2) {
        int N1 = nums1.size(); 
        int N2 = nums2.size();
        int total = N1 + N2;

        double ans = 0;
        if (total == 0)
            return ans;
        if (N1 == 0)
        {
            if (N2 % 2 == 1)
                ans = nums2[N2 / 2];
            else
                ans = 0.5 *(nums2[N2 / 2] + nums2[N2 / 2 - 1]);
            return ans;
        }
        if (N2 == 0)
        {
            if (N1 % 2 == 1)
                ans = nums1[N1 / 2];
            else
                ans = 0.5 *(nums1[N1 / 2] + nums1[N1 / 2 - 1]);
            return ans;
        }

        if (total % 2 == 1) // 總共是奇數長度
        {
            int k = total / 2 + 1;
            ans = findKthNum(nums1, nums2, k);
        }
        else{
            int k1 = total / 2;
            int k2 = k1 + 1;
            ans = 0.5 * (findKthNum(nums1, nums2, k1) + findKthNum(nums1, nums2, k2));
        }
        return ans;
    }

    int findKthNum(vector<int> arr1, vector<int> arr2, int kth) {
        int len1 = arr1.size();
        int len2 = arr2.size();
        vector<int> shortArr = len1 < len2 ? arr1 : arr2;
        vector<int> longArr = len1 >= len2 ? arr1 : arr2;
        int lenS = shortArr.size();
        int lenL = longArr.size();

        if (kth < 1 || kth > len1 + len2) // kth不符合 直接返回
            return -1;

        if (kth <= lenS){
            return getUpMedian(shortArr, 0, kth - 1, longArr, 0, kth - 1);
        }
        if (kth > lenL){
            if (shortArr[kth - lenL - 1] >= longArr[lenL - 1]){ // 長度小的陣列 所有元素都大於 長度大的陣列
                return shortArr[kth - lenL - 1];
            }
            if (longArr[kth - lenS - 1] >= shortArr[lenS - 1]){ // 長度大的陣列 所有元素都大於 長度小的陣列
                return longArr[kth - lenS - 1];
            }
            // 淘汰掉不符合的 得到中位數即可
            return getUpMedian(shortArr, kth - lenL, lenS - 1, longArr, kth - lenS, lenL - 1);
        }

        if (longArr[kth - lenS - 1] >= shortArr[lenS - 1]){ // kth在 longArr中
            return longArr[kth - lenS - 1];
        }
        // 淘汰掉 longArr中不符合的部分
        return getUpMedian(shortArr, 0, lenS - 1, longArr, kth - lenS, kth - 1);
    }

    int getUpMedian(vector<int> arr1, int l1, int r1, vector<int> arr2, int l2, int r2) {
        /*  int N1 = arr1.size();
        int N2 = arr2.size();
        int l1 = 0, r1 = N1 - 1;
        int l2 = 0, r2 = N2 - 1;*/
        while (l1 != r1 || l2 != r2)
        {
            int mid1 = (l1 + r1) / 2;
            int mid2 = (l2 + r2) / 2;

            // 表示 2分查詢要不要包含中間那個數 奇數是0,偶數是1
            int offset = (r1 - l1 + 1) & 1 ^ 1;

            if (arr1[mid1] > arr2[mid2])
            {
                l2 = mid2 + offset;
                r1 = mid1;
            }
            else if (arr2[mid2] > arr1[mid1]){
                l1 = mid1 + offset;
                r2 = mid2;
            }
            else{
                return arr1[mid1];
            }
        }// while

        return arr1[l1] < arr2[l2] ? arr1[l1] : arr2[l2];
    }
};