在兩排序陣列中尋找第K小的數

2022-07-18 00:45:13 字數 4606 閱讀 1355

題目:在兩個排序陣列中尋找第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),額外空間複雜度為o(1)

思路:暴力解法坑定是將兩個陣列放到一起再進行排序,然後再找出第k個,但這樣的時間複雜度肯定超了,一看到logn,就想起肯定與二分查詢有關

看到這個題,我們先來看乙個稍簡單的同類的題,如下:

題目:在兩個長度相同的排序陣列中找到上中位數

給定兩個有序陣列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),額外空間複雜度為o(

1)

先來分析一下這個題:根據時間複雜度的要求,我們首先利用二分的方式來尋找上中位數

1.假定兩陣列分別為arr1[start1,end1] 、arr2[start2,end2]

初始時,start1=0,end1=n-1;start2=0,end2=n-1.

2.如果srart1==end1,那麼也有start2==end2;

表明每個陣列內此時各只有乙個元素,總元素數為2,上中位數為其中較小的那個

所以直接返回 min(arr1[start1],arr2[start2]);

3.如果srart1!=end1,說明此時兩個陣列的長度均大於1,

則令 mid1=(start1+end1)/2 ;mid2=(start2+end2)/2 .來表示兩個陣列的中間位置

這個時候需要分情況討論了;

a.如果arr1[mid1]==arr2[mid2]時,                  直接返回arr1[mid1]或arr2[mid2]

舉個例子來說明一下:

(1).當兩個陣列的長度都為奇數時

arr1=  、其中的a1表示第乙個數,a5表示第5個數,(不表示值)下同

arr2=

此時a3==b3,由於兩個陣列本身是有序的,在a3前面壓著2個數,在b3前面壓著2個數,所以a3,b3前面共壓了4個數,現在要求第5小的數(總共有10個數,故上中位數為5),必然是a3或是b3,而a3==b3,所以直接返回這兩個數中任乙個即可,即返回arr1[mid1]

(2).當兩個陣列的長度都為偶數時

arr1=  

arr2=

此時a2==b2,由於兩個陣列本身是有序的,在a2前面壓著1個數,在b2前面壓著1個數,所以a2,b2前面共壓了2個數,現在要求第4小的數(總共有8個數,故上中位數為4),必然是a2或是b2,而a2==b2,所以直接返回這兩個數中任乙個即可,即返回arr1[mid1]

b.如果arr1[mid1] > arr2[mid2]時,                  

舉個例子來說明一下:

(1).當兩個陣列的長度都為奇數時

arr1=  、其中的a1表示第乙個數,a5表示第5個數,(不表示值)下同

arr2=

此時a3>b3,由於兩個陣列本身是有序的,在b3前面必然至少壓著2個數,而在a3前面至少壓著5個數(a1,a2,b1,b2,b3),所以a3至少應該是第6個數起(因為已經知道前面有5個數肯定比它要小),後面的a4最好情況下也是第7個數起,再後面的a5也必然是大於5的,(因為此時陣列總長度為10,要尋找第5小的數),故此時對於arr1陣列,第5小數必然要在裡面找,而對於arr2陣列,b2 可能是第5小數嗎?不可能,因為在arr2陣列中b2 前只壓了1個數,在ar1陣列中,b2最多只能把2個數(a1,a2)壓在底下,所以b2最好情況下也只能是第4小數,而對於b1 ,由於壓得數更少所以跟不可能,所以從b3 開始才有可能是第5小數

由於兩陣列長度要保持一致,現在來看一下兩陣列中第5小數可能會出現的位置

現在我們來找一下這兩個新陣列的共同的上中位數,也就是這6個數中第3小的數記為a,這個a 代表啥?就是a在這兩段陣列中,會把2個數壓在下面,同時也自然會把原來的arr2陣列中的b1,b2壓在下面,所以a 正好就是第5小的數,也就是我們要求的結果,所以解決問題的方法就是對新的兩個陣列繼續求上中位數,具體做法就是,直接令 end1=mid1,start2=mid2,然後重複求解上中位數就行

(2).當兩個陣列的長度都為偶數時

arr1=  

arr2=

此時a2>b2,由於兩個陣列本身是有序的,a2前面至少壓著3個數,所以a2可能是第4小的數,而對於後面的a3,前面都至少壓了4個數了,必然不是,後面的a4更不用看了,對於陣列arr2,b2最好前面也是只壓了2個數(a1,b1),所以第4小數不可能是b2,更不可能是b1,

由於兩陣列長度要保持一致,現在來看一下兩陣列中第5小數可能會出現的位置

問題同樣轉化為了尋找新陣列的上中位數,所以令end1=mid1,start2=mid2+1.

c.如果arr1[mid1] < arr2[mid2]時,                  

分析方法與b是一樣的(就像b中兩陣列互換了下)

所以,陣列長為奇數時,令start1=mid1,end2=mid2

陣列長度為偶數時,令start1=mid1+1,end2=mid2,重複尋找上中位數就行

所以,我們可以給出整個演算法的**:

1

public

int getupmedian(int arr1,int

arr2)

5int start1=0;6

int end1=arr1.length-1;7

int start2=0;8

int end2=arr2.length-1;9

int mid1=0,mid2=0;10

int offset=0;//

用於判斷過程中陣列的長度的奇偶

11while(start1if(arr1[mid1]26return

math.min(arr1[start1],arr2[start2]);

27 }

現在我們來看一下頭先的那個題,即尋找第k小數

思路:我們先記

長度較短的陣列為shortarr,長度記為lens

長度較長的陣列記為longarr,長度記為lenl

假設shortarr長度為10,表示第乙個數、第2個數、...

假設longarr長度為27,表示第乙個數,...

1.當k<1或k>lens+lenl,則k無效

2.如果k<=lens.

那麼在shortarr中選前面k個數,在longarr中也選前面k個數

則兩段陣列的上中位數就是第k 小數(等價於轉化成了兩個長度相同的陣列的形式)

3.如果k>lenl

如一共有37個數,求第33小的數(33>lenl==27)

在中a5及a5以前的數都不可能是第33小的數,因為就算a5比b27都大,此時a5==32,所以不可能,a5前面的也不可能,對於a6,如果a6>b27,則a6必然是第33小的數,直接返回a6,否則a6不是。同理在中也必然不可能是第33小的數,因為b22最大也只能為22+10=32,所以應從b23開始找,只要b23>a10,則b23必然是第33小,否則b23也不是,如果a6和b23有乙個滿足條件,則可以直接返回,否則說明,都不可能是,應在,這兩個陣列裡找他們的上中位數

4.lens如求第17小的數

在中每個數都有可能

在中b6以前的數必然是不可能的,因為對於b6,最大也只為6+10=16,b18以後的也不可能是,因為他本身就是長陣列中的第18個了

所以長陣列變成了這11個數,如果此時b7>a10,則可以直接返回b7,否則b7不是

再求和上中位數,則為答案

實現**為:

1

public

int getupmedian(int arr1,int start1,int end1,int arr2,int start2,int

end2)else

if(arr1[mid1]19return

math.min(arr1[start1],arr2[start2]);20}

21public

int findkthnum(intarr1,intarr2,int

kth)

25if(kth<1||kth>arr1.length+arr2.length)

28intlongs=arr1.length>=arr2.length?arr1:arr2;

29intshorts=arr1.lengtharr1:arr2;

30int l=longs.length;

31int s=shorts.length;

32if(kth<=s)

35if(kth>l)

42if(longs[kth-s-1]>=shorts[s-1

])45

return getupmedian(shorts,0,s-l,longs,kth-s,kth-1

);46 }

參考:《程式設計師**面試指南》左程雲

快速排序 尋找無序陣列中的第k大的數

思路是利用快速排序 因為快速排序的分治思想可以將查詢的範圍縮小 快速排序的思想 low為陣列的起始點,high為陣列的尾部點。交替掃瞄 1.固定陣列的第乙個數為定點,從陣列的尾部high開始往左查詢,直到第乙個比定點小的數,和定點交換,因此當前點為空 high 2.從陣列的起始處,low找到第乙個比...

尋找單個無序陣列中第K小的數字

1 排序 對陣列進行排序 然後前k個元素就是需要查詢的元素,排序的方法可以採用快速排序,但是我們知道在快速 排序中如果已經是有序的陣列,採用快速排序的時間複雜度是o n 2 為了解決這種問題,通常選擇隨機選擇乙個 陣列值pivot作為基準,將陣列分為s1 pivot和s2 pivot,這樣就能避免快...

尋找第K小的數

尋找第k小的數屬於順序統計學範疇,通常我們可以直接在o nlgn 的時間內找到第k小的數,使用歸併排序或者堆排序對輸入資料按從小到大進行排序,然後選擇第k個即可。然而,我們還有更好的演算法。首先來看乙個簡單的問題,在乙個有n個元素的集合中,需要多少次比較才能確定其最小值呢?這可以很容易退出需要n 1...