拿起算法的鋼筆: 找出兩個有序數組的中位數

給定兩個大小爲 m 和 n 的有序數組 nums1 和 nums2算法

題目:請你找出這兩個有序數組的中位數,而且要求算法的時間複雜度爲 O(log(m + n))。

你能夠假設 nums1 和 nums2 不會同時爲空。數組

示例 1:bash

nums1 = [1, 3]動畫

nums2 = [2]ui

則中位數是 2.0spa

示例 2:code

nums1 = [1, 2]cdn

nums2 = [3, 4]視頻

則中位數是 (2 + 3)/2 = 2.5blog

分析:

常規作法, 是 O(m+n)

兩個有序數組,合併成一個有序數組,取中位數, 思路很清晰

這裏只要取中位數,只要保證,這個數字左邊的元素個數( 數組一左邊 i 個+數組二左邊 j 個 )與右邊的元素個數相等,這個數字左邊的元素都小於右邊的元素,

就能夠認爲,這個數字是咱們想要的

先分片, 保證找到的中位數,這個數字左邊的元素個數( 數組一左邊 i 個+數組二左邊 j 個 )與右邊的元素個數相等

由於是中間位置的數字, 若是第一個數組 nums1 取 i 個,( 0 <= i <= m ), 那麼第二個數組 nums2 裏面取 j 個, ( 0 <= j <= n ),

i 與 j 知足必定的關係 i + j = ( m + n )/2 , 或者 i + j = ( m + n + 1)/2 , 由於 m + n 多是奇數,也多是偶數。 那麼 j = ( m + n + 1 ) / 2 - i

再取值,這個數字左邊的元素都小於右邊的元素

i 和 j 把兩個數組,各分紅兩片,出現了四個關鍵的數字,

數組一左邊最大,num1LeftMax

數組一右邊最小,num1RightMin

數組二左邊最大,num2LeftMax

數組二右邊最小,num2RightMin

若是 num1LeftMax <= num2RightMin, num2LeftMax <= num1RightMin, 就找到咱們想要的中位數了,由於 num1 是有序數組,num1LeftMax 固然小於 num1RightMin,一樣的 num2LeftMax < num2RightMin

O(m), 由於這就是二分搜索,搜索條件不是很直接

爲何是 O(m), 由於這就是二分搜索。

通常咱們的二分搜索是一個有序數組,查找元素,每一次查找,把搜索範圍縮減一半。經過移動上邊界和下邊界

就是比較條件相對簡單,直接比元素大小

這道題其餘與基礎的二分查找一致, 比較條件有些變化

若是 num1LeftMax > num2RightMin, 數字一左邊的大了,就是 i 大了,就要移動右邊界,就是右邊界變小

(左邊界只能右移,只能變大。右邊界只能左移,只能變小)

其餘狀況,相似處理

拿起算法的鋼筆,跑一遍

示例 3:

nums1 = [ 1, 3,8,9,15 ]

nums2 = [ 7, 11, 18, 19, 21,25 ]

中位數是 11

111

左邊有 5 個元素, m = 5,

右邊有 6 個, n = 6

222

數組一右邊最小,num1RightMin < 數組二左邊最大,num2LeftMax 就是 i 小了,左邊界右移, low = 3

333

如今知足要求了,m + n 是奇數,左邊多一個,選數組一左邊最大和數組二左邊最大中較大的,就是 11

拿起算法的鋼筆,再跑一遍,爲了印象深入

示例 4:

nums1 = [ 23, 26,31,35 ]

nums2 = [ 3, 5, 7, 9, 11,16 ]

中位數是 13.5, 11 和 16 的平均值

444

左邊有 4 個元素, m = 4,

右邊有 6 個, n = 6

666

數組一左邊最大,num1LeftMax > 數組二右邊最小,num2RightMin 就是 i 大了,右邊界左移, high = 1

666

左邊一個元素都不要,默認數組一左邊最大爲負無窮,num1LeftMax = Number.MIN_SAFE_INTEGER,

如今知足要求了,m + n 是偶數,找出中間兩個 11 與 16,求平均值爲 13.5

PS: 我的看,看書和看算法動畫,不錯,就是少了一點參與感。 拿起鋼筆,寫寫畫畫,須要保證結果一致嘛,我感受,理解的好一些

代碼以下:

選短的數組處理,處理快,還保證了 j 必定大於 0 (由於 n > m),避免了一些邏輯處理。

裏面處理了一些邊界條件, i = 0, 第一個數組左邊一個元素都不要,i = m, 第一個數組右邊一個元素都不要

m + n 的值是奇數,這個好處理一點,只須要找出一個元素

m + n 的值是偶數,須要找出兩個元素

var findMedianSortedArrays = function (nums1, nums2) {
    if (nums1.length > nums2.length) {
        [nums1, nums2] = [nums2, nums1]
    }
    const arr1Length = nums1.length, arr2Length = nums2.length;
    let low = 0, high = arr1Length;
    const halfLen = Math.floor((arr1Length + arr2Length + 1) / 2);

    while (low <= high) {
        let i = Math.floor((low + high) / 2); 
        let j = halfLen - i;
        let num1LeftMax = i == 0 ? Number.MIN_SAFE_INTEGER : nums1[i - 1]
        let num1RightMin = i == arr1Length ? Number.MAX_SAFE_INTEGER : nums1[i]
        let num2LeftMax = j == 0 ? Number.MIN_SAFE_INTEGER : nums2[j - 1]
        let num2RightMin = j == arr2Length ? Number.MAX_SAFE_INTEGER : nums2[j]
        if (num1LeftMax <= num2RightMin && num2LeftMax <= num1RightMin) {
            var answer = 0
            if (Math.round((arr1Length + arr2Length) % 2) == 1) {
                answer = Math.max(num1LeftMax, num2LeftMax)
            }
            else {
                // Math.round((arr1Length + arr2Length) % 2) == 0
                let leftMax = Math.max(num1LeftMax, num2LeftMax)
                let rightMin = Math.min(num1RightMin, num2RightMin)
                answer = (leftMax + rightMin) / 2
            }
            return answer
        }
        else if (num1LeftMax > num2RightMin) {
            high = i - 1
        }
        else { // num2LeftMax > num1RightMin
            low = i + 1
        }
    }
    return 0;
};

複製代碼

我還喜歡看視頻,有一個 youtube ,連接是 www.youtube.com/watch?v=LPF… .

本文能夠做爲該視頻和 Leatcode 官方題解的補充, 官方題解: leetcode.com/problems/me…

相關文章
相關標籤/搜索