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

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

查找两个已经排好序的数组的第k大的元素

發(fā)布時間:2024/9/30 编程问答 22 豆豆
生活随笔 收集整理的這篇文章主要介紹了 查找两个已经排好序的数组的第k大的元素 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

http://www.cnblogs.com/buptLizer/archive/2012/03/31/2427579.html

給出兩個排好序的數(shù)組 ,不妨設(shè)為a,b都按升序排列,及k的值,求出第k大的那個元素。

分析這個題目,如果題目沒有時間復(fù)雜度的要求,我們可以定義兩個指針i,j分別指向a,b,如果a[i]<b[j]則i++否則

j++,這個記錄下走了多少步,如果==k步,則找到了第k大的元素,復(fù)雜度為O(k).

那么如果有復(fù)雜度的要求,要求為O(log(len_a+len_b))呢,這個就得好好考慮,怎么利用二分來解決這個問題。


?判斷a[mid_a] 與 b[mid_b]的關(guān)系
?如果a[mida] < b[mid_b]

?1)k小于等于mida + midb + 1,那么b數(shù)組從mid_b開始就沒有用了,縮小b的搜索范圍
?2)k大于mida + midb + 1, 那么a數(shù)組從low到mid_a開始就沒用了,縮小a的搜索范圍
?3)終止條件是 a搜索完 返回b中元素或者相反

int get_k_from_sorted_array2(int* a, int*b, int la, int ha, int lb, int hb, int k) {if(la > ha)return b[lb + k - 1];if(lb > hb)return a[la + k - 1];int mida = (la + ha)>>1;int midb = (lb + hb)>>1;int num = mida- la + midb - lb + 1;cout<<la<<" "<<ha<<" "<<lb<<" "<<hb<<" "<<num<<" "<<a[mida]<<" "<<b[midb]<<endl;if(a[mida] <= b[midb]){if(k <= num)return get_k_from_sorted_array2(a, b, la, ha, lb, midb - 1, k);elsereturn get_k_from_sorted_array2(a, b, mida + 1, ha, lb, hb, k - (mida - la + 1));}else{if(k <= num)return get_k_from_sorted_array2(a, b, la, mida - 1, lb, hb, k);elsereturn get_k_from_sorted_array2(a, b, la, ha, midb + 1, hb, k - (midb - lb + 1));} } int _func2(int* a, int a_len, int* b, int b_len, int k) {int rst = 0;if(a_len + b_len < k)return -1;int p1 = a_len > k ? k : a_len;int p2 = b_len > k ? k : b_len;cout<<p1<<" "<<p2<<endl;rst = get_k_from_sorted_array2(a, b, 0, p1 - 1, 0, p2 - 1, k);return rst; }


還有更霸氣的解答:

http://blog.csdn.net/beiyeqingteng/article/details/7533304

前言:

這道題是一道非常常見的面試題,也是一道能夠考察一個人的編程能力和算法的一道題。如果要求復(fù)雜度為 O(k), 是比較容易做出來的,但是,一般來講,面試官要求給出更低復(fù)雜度的算法。網(wǎng)上有很多不同的解法,但是,總的來講,那些程序考慮的因素太多,比較難懂,而且結(jié)構(gòu)很亂。在這里寫出自己的方法。本文的算法復(fù)雜度為 O(lg K)。?

PS. 如果你沒有見過這個題目,并且能夠在30分鐘內(nèi)寫出沒有bug的,復(fù)雜度為 O(lg K) 的程序,我愿意拜你為師,呵呵。

問題:

給定兩個已經(jīng)排序的數(shù)組(假設(shè)按照升序排列),然后找出第K小的數(shù)。比如數(shù)組A = {1, 8, 10, 20}, B = {5, 9, 22, 110}, 第 3 小的數(shù)是 8.

分析:

### 最好自己先動手寫一寫,然后再看后面的分析,因為自己寫過一遍以后,才能發(fā)現(xiàn)這個程序的難處在哪里。###

因為兩個數(shù)組已經(jīng)排序了,所以,要找出第 k 小的值,我們可以給每個數(shù)組設(shè)置一個“指針”, 比如pa, pb。在初始狀態(tài),兩個指針分別指向第一個起始值,即pa = 0, pb = 0。然后,我們開始進(jìn)行比較,如果A數(shù)組的值比B數(shù)組的值小, 把A數(shù)組的指針pa向前移動,然后再進(jìn)行比較。每次移動,我們都能夠得到當(dāng)前第 i 小的值(隨著pa,pb 的移動,i 會逐漸變大)。

比如對于數(shù)組A = {1, 8, 10, 20}, B = {5, 9, 22, 110},初始時,pa = 0; pb = 0,因為(A[pa] = 1) < (B[pb] = 5), 所以,第 1 小的值為 1,這個時候,我們會把 pa 向右移動,即 pa = 1, 并且 pb 保持不變: pb = 0. 然后再次比較A[pa] 和 B[pb] 的值,因為 ?(A[pa] = 8) > (B[pb] = 5), 所以,第 2 小的值是 5, 然后,我們增加 pb 的值。請注意,如果我們用一個變量來保存當(dāng)前第 i 小的值 (隨著pa, pb的移動,i 的值也會增加,那個變量保存的值也會改變)。那么,當(dāng)pa + pb = k 的時候,那么那個變量保存的一定是第 k 小的值

這里要注意的是,當(dāng)一個數(shù)組的指針已經(jīng)“到頭”了,這個時候怎么進(jìn)行越界處理呢?如果我們用if 來處理,在程序里會有一大堆的 if 判斷語句,太難看了。我們這里可以用一個簡單的判斷語句就可以處理了。

[java]?view plaincopy
  • int?Ai?=?(pa?==?A.length)???Integer.MAX_VALUE?:?A[pa];??
  • int?Bj?=?(pb?==?B.length)???Integer.MAX_VALUE?:?B[pb];??
  • (上面這個語句太牛逼了,但很可惜不是我自己寫的,這是向人家學(xué)的。)有了這個語句,我們不用任何if語句,而且, 最最重要的是,我們可以從一開始就用這個語句來確定A[pa]和B[pb]的值,所以,從頭到尾,不會有任何的改變,也不會有越界的情況出現(xiàn)(為何不會越界?看完后面的代碼就知道了。) 。

    好了,有了上面的分析,下面的代碼就不難理解了。

    [java]?view plaincopy
  • public?static?int?kthTwoSortedArray(int[]?A,?int[]?B,?int?k)?throws?Exception?{??
  • ??????
  • ????if?(k?>?A.length?+?A.length?||?k?<?1)?throw?new?Exception("out?of?range!");??
  • ??????
  • ????//?pointer?of?array?A??
  • ????int?pa?=?0;??
  • ????//?pointer?of?array?B??
  • ????int?pb?=?0;??
  • ????//store?the?kth?value??
  • ????int?kthValue?=?0;??
  • ??????
  • ????while?(pa?+?pb?!=?k)?{??
  • ????????int?Ai?=?(pa?==?A.length)???Integer.MAX_VALUE?:?A[pa];??
  • ????????int?Bj?=?(pb?==?B.length)???Integer.MAX_VALUE?:?B[pb];??
  • ??????????
  • ????????if?(Ai?<?Bj)?{??
  • ????????????pa++;??
  • ????????????kthValue?=?Ai;??
  • ????????}?else?{??
  • ????????????pb++;??
  • ????????????kthValue?=?Bj;??
  • ????????}??
  • ????}??
  • ????return?kthValue;??
  • }??

  • 上面這個程序的復(fù)雜度是O(k),分析很簡單,就不再講了。


    現(xiàn)在再來看如何得到 O(lg K) 的算法。

    在上面的程序里,我們是逐一比較數(shù)組A 和數(shù)組B的值,但是,這樣做還是太慢了,因為兩個數(shù)組是已經(jīng)排過序的,我們完全可以利用二分查找的方法來解決這樣的問題。但是具體介紹怎么做之前,先講一些預(yù)備知識。

    對于數(shù)組A 、 B , 如果 B[pb] < A[pa] && B[pb] > A[pa - 1], 那么 B[pb] 一定是第 pa + pb + 1 ?小的數(shù)。 比如數(shù)組A = {1, 8, 10, 20}, B = {5, 9, 22, 110},?pa = 2, pb = 1, 這時,(B[pb] = 9) < (A[pa] =10) && (B[pb] = 9) > (A[pa - 1] = 8) ,那么,B[pb] = 9 一定是第 pa+pb+1 = 4 小的數(shù)。 換一句話說,如果我們要找第 k 小的數(shù),那么, pa + pb ?= k - 1。而且,B[pb] < A[pa] && B[pb] > A[pa - 1] 或者?A[pa] < B[pb] && A[pa] > B[pb - 1] 中的其中一個必須成立。 如果不成立, 我們需要移動pa 和 pb 的位置來使得其中的一個式子成立 (參看代碼)。這是本題算法的本質(zhì)。

    但是,這里也會出現(xiàn)”邊界“問題,比如,k = 1, 那么 pa + pb ?= 1 - 1, 即 pa + pb = 0. 因為 pa >= 0, pb >=0, 所以,我們得到 pa = 0, pb = 0. 那么這樣的話, 求A [pa-1]值的時候 就會有exception. 同理,對于數(shù)組A = {1, 8, 10, 20}, B = {5, 9, 22, 110},當(dāng)k = 8 的時候, pa + pb ?= 8 - 1, 即 pa + pb = 7, 但是,pa <= 3, pb <= 3。邊界的處理是這道題最最麻煩的地方。對于這個問題,我們用下面這段代碼來解決。

    [java]?view plaincopy
  • int?Ai_1?=?(pa?==?0)???Integer.MIN_VALUE?:?A[pa-1];??
  • int?Bj_1?=?(pb?==?0)???Integer.MIN_VALUE?:?B[pb-1];??
  • int?Ai???=?(pa?==?A.length)???Integer.MAX_VALUE?:?A[pa];??
  • int?Bj???=?(pb?==?B.length)???Integer.MAX_VALUE?:?B[pb];??
  • 通過上面這段代碼,我們實際上是把數(shù)組延長了,每個數(shù)組多了兩個值Integer.MIN_VALUE,?Integer.MAX_VALUE, 這樣,當(dāng)pa = 0 是,我們也可以得到A[pa - 1] 的值:Ai_1 = ((pa == 0) ? Integer.MIN_VALUE : A[pa-1]); 當(dāng) pa =??A.length 時,我們可以得到 A[pa]的值:Ai =?(pa == A.length) ? Integer.MAX_VALUE : A[pa]。 這樣,我們就不用擔(dān)心越界的問題了。

    有了上面的分析,代碼就容易寫出來了。

    在程序里,我們設(shè)置 pa 的初始值為Math.min(A.length, k - 1),然后,通過增加或者減少pa 的值,來使得 B[pb] < A[pa] && B[pb] > A[pa - 1] 或者?A[pa] < B[pb] && A[pa] > B[pb - 1] ?成立,代碼中, delta 指的是 pa 的變化量,每次遞歸以后,delta的值變成一半。 在程序中用delta完成二分查找


    public class FindKthSmallestValue {public static int findKthSmallest(int[] A, int[] B, int pa, int delta, int k) {int pb = (k - 1) - pa;//保證pb+ba = k -1int Ai_1 = ((pa == 0) ? Integer.MIN_VALUE : A[pa-1]);int Bj_1 = ((pb == 0) ? Integer.MIN_VALUE : B[pb-1]);int Ai = ((pa == A.length) ? Integer.MAX_VALUE : A[pa]);int Bj = ((pb == B.length) ? Integer.MAX_VALUE : B[pb]);//滿足其中之一條件,就返回if (Bj_1 <= Ai && Ai <= Bj) return Ai;if (Ai_1 <= Bj && Bj <= Ai) return Bj;//delta表示pa的變化量(pa通過加減delta實現(xiàn)pa的增加或者減少)//如果 Ai > Bj, 我們要縮小pa的值,即 pa = pa - delta//因為 pb = (k - 1) - pa, 所以,如果delta的值太大,//pa會變得很小,因而 可能會導(dǎo)致 pb > B.length. 所以需要處理一下。// 對于pa = pa + delta 的處理也是一樣if (Ai > Bj) {pa = ((k - 1) - (pa - delta) > B.length) ? k - 1 - B.length : pa - delta;//防止把pa調(diào)整的過小,而導(dǎo)致pb+pa<k-1return findKthSmallest(A, B, pa, (delta + 1) / 2, k);} else {pa = (pa + delta > A.length) ? A.length : pa + delta;return findKthSmallest(A, B, pa, (delta + 1) / 2, k); }}public static void main(String[] args) {int[] A = {1, 8, 8, 10, 20};int[] B = {5, 8, 8, 9, 22, 110};int k = 7;int pa = Math.min(A.length, k - 1);System.out.println(findKthSmallest(A, B, pa, (pa + 1) / 2, k));} }


    與50位技術(shù)專家面對面20年技術(shù)見證,附贈技術(shù)全景圖

    總結(jié)

    以上是生活随笔為你收集整理的查找两个已经排好序的数组的第k大的元素的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。