日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

Leetcode-Median of Two Sorted Arrays

發布時間:2024/4/11 编程问答 28 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Leetcode-Median of Two Sorted Arrays 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

    • 前言
    • 題目分析1
      • 算法的正確性
      • 代碼
      • 效率
    • 題目分析2
      • 算法的正確性
      • 代碼
      • 效率
    • 推廣
      • 結語

前言

Leetcode刷到150道了,各種題型都已經練習了一遍,沒有必要再去刷數量了!分類總結解題方法,完善知識體系已經是刻不容緩了。尤其是在看了《暗時間》之后,深有感觸??偨Y、反思自己的思維過程也許是最重要的。對每道題進行深加工,抽象出一般的概念,得到一般的解題策略。這個過程才是最重要的,是沉淀思想的絕好途徑。

先簡單摘一些常用的解題方法,以后每碰到難題的時候,都要想一下用這些方法是否可以解決:

  • 時刻不忘未知量
    時刻要想到自己的問題是什么,要求什么。

  • 用特例啟發思考
    構造一個合適的實例,可能會發現一般的規律。

  • 反過來推導
    設立未知數,從結論出發,向已知條件靠擾。

  • 試錯

  • 調整題目的條件
    去掉一個條件,觀察區別,再放上那個條件,感覺到題目的內在結構上的某種約束,進而得到答案。
  • 求解一個類似的題目
    為了優化腦中的知識結構,我們在記憶掌握和分析問題的時候都應該盡量抽象地去看待,這樣才能建立知識的本質聯系。
  • 列出所有可能與題目有關的定理或性質
    比如這道題目,可以列出這樣的性質:中位數是數組中最中間的數。如果元素總數為奇數,它左邊所有元素的個數和右邊所有元素的個數相等;如果為偶數,則將所有元素平分成兩左右兩部分,兩部分元素個數相等, 中位數為最中間兩者的均值。
  • 考察反面,考察其他所有情況
  • 將問題泛化
    這道題應該要進行泛化,比如如果要求兩個排序元素里的第K大元素怎么求?如果是n個排序數組呢?

題目分析1

Leetcode-CPP_p14可以從結論來推導方法:題目要求用log(m+n)的復雜度,而中位數的序號為i=m+n2,要想達到要求的復雜度,則每次查找都應該使i減半,即要用到二分搜索。那怎樣才能用到二分搜索呢?這一步還不是那么明顯,答案是將原問題泛化,尋找兩個排序數組的第k小的數,然后每步排除k/2個數,則最后可以達到復雜度要求。

假設A,B兩個數組的元素個數都大于k/2,那么將A,B的第k個元素,也就是A[k2?1]B[k2?1]作比較的話,

?????A[0]B[0]A[1]?B[1]?A[k2?1]B[k2?1]A[k2]?B[k2]??????

可以得到:

???????A[k2?1]<B[k2?1],A[k2?1]>B[k2?1],A[k2?1]==B[k2?1],(1)(2)(3)

對于情形(1)A[0]?A[k2?1]一定是排在B[k2?1]之前,因此A[0]?A[k2?1]絕對不會是第k小的數,可以在下一輪尋找中去掉,因此下一輪比較將變成:
?????A[k2]B[0]?B[1]?A[k2+k4?1]B[k4?1]?B[k4]??????

這里我們不能排除B中的元素,是因為我們僅僅知道A[k2?1]B[k2?1]的大小關系,而不知道A[k2?1]B[0]的關系,B[0]可以很大,以至于大于A[k2?1],而這個時候,其實我們是得不出進一步的結論的,因為我們還是不知道B[0]A[k2?1]后面元素的關系。當然,另一方面,B[0]可以比較小,以至于當它增加到B[k2?1]時只比A[k2?1]大了一點點,且小于A[k2],那么B[k2?1]就是我們要找的第k小的數,只是找到它還需要再遞歸幾次。而這并不難分析。

因為我們是要尋找第k小的數,永遠不要忘了我們的目的是什么——走得太遠,不要忘了當初是為什么出發!而我們已經排除了k2個數,因此下一步是尋找第k2(這里的第k2是指包括當前元素的元素個數)小的數,因而又可以排除一半的數,即k4

情形(2)的分析類似;

而情形(3)就更簡單了,直接可以得到要找的數就是A[k2?1]。因為一定可以得到下面的排列:

A[0]?A[k2?2]?B[0]?B[k2?2]?A[k2?1]?B[k2?1]

雖然我們不知道A?B中的前k?2個數的具體順序,但是最后兩個數一定是A[k2?1],B[k2?1],而最后一個數正是我們要找的第k小的數。

算法的正確性

如何證明算法的正確性呢?
每次遞歸都會排除一半的元素或者排除掉整個數組,即當k2>m,最后一定會得到正確的結果。

代碼

int getKth(int a[], int m, int b[], int n, int k) {if (m > n)return getKth(b, n, a, m, k);if (0 == m)return b[k-1];if (1 == k)return min(a[0], b[0]);int i = min((k+1)/2, m);/*if (a[i-1] < b[i-1])return getKth(a+i, m-i, b, n, k-i);else if (a[i-1] > b[i-1])return getKth(a, m, b+i, n-i, k-i);*/int j = k-i;if (a[i-1] < b[j-1])return getKth(a+i, m-i, b, n, k-i);else if (a[i-1] > b[j-1])return getKth(a, m, b+i, n-i, k-j);elsereturn a[i-1]; }double findMedianSortedArrays(int* nums1, int nums1Size, int* nums2, int nums2Size) {int total = nums1Size+nums2Size;if (total & 1) //oddreturn getKth(nums1, nums1Size, nums2, nums2Size, total/2+1);else //evenreturn (getKth(nums1, nums1Size, nums2, nums2Size, total/2+1) + getKth(nums1, nums1Size, nums2, nums2Size, total/2))/2.0; }

代碼中注釋的地方是有問題的,如果只是比較A[i?1]B[i?1],那么無論i是等于k2還是等于k+12,最后都是不能直接用后面三種情況來處理的。所以我們還需要一個變量j=k?i來保證目前我們比較的元素個數為k。還是那句話,不要忘了最初的目的是什么。

所以這里的關鍵在于選出k個數,比較每個一維數組的最后一個元素的大小。對于kn大于一維數組的長度m的情形,就會越界,這時只能取m個元素了,那另外一個數組就必須取k?m個元素了,對于n==2時,顯然k?m對于第2個數組是不越界的。但對n>2的情形,則情況會復雜很多。

下面是用vector加上迭代器的代碼:

int getKthOfVectors(vector<int>& nums1, vector<int>::iterator it1, vector<int>& nums2, vector<int>::iterator it2, int k) {int sz1 = nums1.end()-it1;int sz2 = nums2.end()-it2;if (sz1 > sz2)return getKthOfVectors(nums2, it2, nums1, it1, k);if (0 == sz1)return *(it2+k-1);if (1 == k)return min(*it1, *it2);int i = min((k+1)/2, sz1);int j = k-i;if (*(it1+i-1) < *(it2+j-1)){it1 += i;return getKthOfVectors(nums1, it1, nums2, it2, k-i);} else if (*(it1+i-1) > *(it2+j-1)){it2 += j;return getKthOfVectors(nums1, it1, nums2, it2, k-j);} elsereturn *(it1+i-1); }double findMedianSortedArrays(vector<int>& nums1, vector<int>& nums2) {int total = nums1.size()+nums2.size(); if (total & 1) //oddreturn getKthOfVectors(nums1, nums1.begin(), nums2, nums2.begin(), (total+1)/2);else //evenreturn (getKthOfVectors(nums1, nums1.begin(), nums2, nums2.begin(), total/2+1)+getKthOfVectors(nums1, nums1.begin(), nums2, nums2.begin(), total/2))/2.0; }

效率

假定n是要找的第n小的數。則:
T(n)=T(n/2)+O(1),由主定理?T(n)=logn。

題目分析2

根據discuss里分享的解答,還可以利用中位數的這一性質:中位數兩邊的元素個數相等(或相差1)。列出這一性質并不難,難就難在怎么根據這一性質繼續往下走。

????A[0]B[0]left?partA[1]?B[1]?A[i?1]B[j?1]right?partA[i]?B[j]?A[m?1]B[n?1]????

當左右兩部分的元素個數相等或者相差1時,而且A[i]>B[j?1],B[j]>A[j?1],那么中位數就不難找出來了。因此我們只要找出i

由此,可列方程i+j=m?i+n?j或者i+j=m?i+n?j+1

{i+j=m?i+n?j,i+j=m?i+n?j+1,(m+n)(m+n)

?

{j=m+n2?i,j=m+n+12?i,(m+n)(m+n)

?

j=m+n+12?i(將m+n為奇數和偶數統一起來)

因此我們只要在0~m中尋找i,就可以得到解答,而且由于是尋找中位數,它一定是存大的,就是說我們用binary search來尋找i,是一定能找到的。值得注意的是,這里的i[0,m],當i==0時,A全部在left part,當i==m時,A全部在rigth part部分。

算法的正確性

每次查找,要么找到i,要么會縮小查找范圍,而i一定是存在的,所以最后一定能找到i。

代碼

double findMedianSortedArrays(vector<int>& nums1, vector<int>& nums2) {int sz1 = nums1.size();int sz2 = nums2.size();if (sz1 > sz2)return findMedianSortedArrays(nums2, nums1);int imin = 0;int imax = sz1;int i, j;while (imin <= imax){i = (imin+imax)/2;j = (sz1+sz2+1)/2 - i;if (i > 0 && j < sz2 && nums2[j] < nums1[i-1])imax = i-1;else if (j > 0 && i < sz1 && nums1[i] < nums2[j-1])imin = i+1;else break;}int num1;if (0 == i)num1 = nums2[j-1];else if (0 == j)num1 = nums1[i-1];elsenum1 = max(nums1[i-1], nums2[j-1]);if ((sz1+sz2) & 1) //oddreturn num1;int num2 = min(nums1[i], nums2[j]);return (num1+num2)/2.0; }

注意:代碼最后返回時用到除法,除數要用2.0,否則返回的是int類型轉換到double,結果錯誤。

效率

二分查找的效率當然是log2min(m,n)

推廣

如果是在n個已排序的數組,尋找第k小的數,該怎么求呢?
根據思路1,我們可以比較每個數組的第kn個數,如果全部相等,則找到第k小的數;否則,可以排除(n?1)kn個數,只有最大的那個元素所在的數組不能排除掉。

上面所說的是理想情況下,實際寫代碼的時候要考慮的東西稍復雜一些,當數組的元素個數小于kn時,明顯就會越界。再有首先得保證,所有數組的元素總數一定大于k的。

因此,可以推廣為找出二維vector中的第k小的數。

接口為:

double findMedianSortedArrays(vector<vector<int>> &nums, int k)

效率又該怎么計算呢?
這里nk均有可能是變量,為了更好的與主定理對應,我們用
n表示輸入的規模,即

(1)如果是在n個已排序的數組,尋找第b小的數

復雜度與n其實沒有關系,只與b有關,因此T(n)=O(1)。

(2)如果是在b個已排序的數組,尋找第n小的數

每次遞歸后n都會變成原來的1b?T(n)=T(n/b)+O(1),由主定理?T(n)=logn
最壞情況下,每次只能排除一個數,那么時間復雜度就會降為O(n)

結語

如果n維數組的每維的長度相等,還比較好辦。如果每維的長度不等,對于最好情況下的每次遞歸后規模變成原來的1n就會退化成每次遞歸后規模只減了1。所以,以上的思路只對2個已經排序的一維數組有比較好的效果。

不管怎么說,第一篇博客,加油!!!

總結

以上是生活随笔為你收集整理的Leetcode-Median of Two Sorted Arrays的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。