求陣列中第k個最小數

2021-10-04 07:48:27 字數 2996 閱讀 7609

一、問題描述

給定乙個陣列,陣列中的資料無序,在乙個陣列中找出其第k個最小的數,例如對於陣列x,x = ,則其第2個最小的數為2。

二、解題思路

本演算法跟快排的思想相似,首先在陣列中選取乙個數centre作為樞紐,將比centre小的數,放到centre的前面將比centre大的數,放到centre的後面。如果此時centre的位置剛好為k,則centre為第k個最小的數;如果此時centre的位置比k前,則第k個最小數一定在centre後面,遞迴地在其右邊尋找;如果此時centre的位置比k後,則第k個最小數一定在centre後面,遞迴地在其左邊尋找。

注意:centre的位置=其下標值+1,因為陣列中的第乙個元素的下標為0。

從上面的描述中,我們可以看到這個演算法運用了減治的方法求解。減治的思想與分治非常相似,同樣是在一次操作中,削減問題的規模,只是分治把每個子問題求解後,要合併每個子問題的解才能得到問題,而減治的方法,卻不用合併子問題的解,子問題的解,直接就是原問題的解。舉個例子來說,就像快排和二分查詢演算法,前者是分治,後者是減治。因為快排要等到所有的子陣列都排完序,原陣列才有序,而二分查詢卻不用,它每執行一次查詢,直接丟棄一半的陣列,而不用合併子問題的解。不過也有不少書,把他們都歸為分治法。

三、**實現

考慮到**的通用性,使用了模板函式,如果看不懂模板函式,則只需要忽略template,並把t看作是乙個型別即可。**如下:

//返回陣列中的第k個最小元素的啟動函式,注意會破壞原陣列

template

<

typename t>

t findthekmin

(t *x, int x_size, int k)

;

//實現查詢陣列中第k個最小元的功能函式

template

<

typename t>

t thekmin

(t *x, int left, int right, int k)

;

template

<

typename t>

t findthekmin

(t *x, int x_size, int k)

template

<

typename t>

t thekmin

(t *x, int left, int right, int k)

//把樞紐放在正確的位置

swap(x[i], x[right]);

//如果此時centre的位置剛好為k,則centre為第k個最小的數

if(i+

1 == k)

return x[i];

else

if(i+

1< k)

else

}

**說明:

在上面的**中,我們要注意,thekmin函式的最後的if-else,這個演算法不同於快排,當樞紐不是要找到元素時,它只會選擇其中乙個方向的子陣列繼續尋找,而不像快排那樣,會在兩個方向的子陣列中繼續。從上面的**來看,其執行速度應該在使用相同選取樞紐的策略的快排之上,時間複雜度為o(n)。

同時,當k值不合理時,我們只能返回第0個元素,這點有一點的不合理,但是,我不知道該返回乙個什麼樣的合適的值,因為它是泛型的。

其實,這段**有兩個缺陷,第乙個,就是在查詢時,破壞了陣列原來的資料(交換了位置);第二個是,當型別t的複製和構造開銷較大時,直接多次交換兩個元素,可能會帶來相當大。

另一種實現

下面,再來看看另一種實現,演算法的思想和策略相同,但是使用了乙個跟蹤陣列track,用來跟蹤使用第一種方法下的資料的交換情況,利用跟蹤陣列的元素交換代替原陣列中元素的交換,解決了上面提到的兩個問題。它的實現如下:

//返回陣列中的第中個最小元素的下標的啟動函式,不破壞原陣列

template

<

typename t>

intindexofkmin

(const t *x, int x_size, int k)

;

//實現查詢陣列中第k個最小元下標的功能函式

template

<

typename t>

intthekmin

(const t *x, int *track, int left, int right, int k)

;

template

<

typename t>

intindexofkmin

(const t *x, int x_size, int k)

template

<

typename t>

intthekmin

(const t *x, int *track, int left, int right, int k)

//把樞紐放在正確的位置

swap(track[i], track[right]);

//如果此時centre的位置剛好為k,則centre為第k個最小的數,

//返回其在真實陣列中的下標,即track[i]

if(i+

1 == k)

return track[i];

else

if(i+

1< k)

else

}

**說明:

從上面的**,我們可以看出,這個函式是返回陣列中的第k個最小元的下標,所以當k不合理時,就可以返回-1來表示這個錯誤,同時,它使用了乙個跟蹤陣列,track陣列中的內容,實質是原陣列中資料的乙個索引,利用跟蹤陣列的元素的交換來代替了原陣列元素的交換,因為該跟蹤陣列的資料型別是int,所以其交換速度相當快,從而解決了上面提到的兩個問題。

從上面的**,我們也可以看到,其時間複雜度與前面的實現是一樣的,也為o(n),但是,這個實現方法卻帶來了一定的空間開銷,它開闢了乙個與原陣列元素個數相等的一維陣列,用於跟蹤原陣列中的元素的交換情況。

至於在實際中,要使用哪一種演算法,取決於使用者的需要!

有序矩陣中的第k個最小陣列和

leetcode題目 給你乙個 m n 的矩陣 mat,以及乙個整數 k 矩陣中的每一行都以非遞減的順序排列。你可以從每一行中選出 1 個元素形成乙個陣列。返回所有可能陣列中的第 k 個 最小 陣列和。示例 1 輸入 mat 1,3,11 2,4,6 k 5 輸出 7 解釋 從每一行中選出乙個元素,...

陣列中的第k小數

描述 以盡量高效率求出亂序中的k小數 輸入 第一行 陣列長度 第二行 陣列元素 空格隔開 第三性 第幾小的數 輸出 第k小的數 樣例輸入 5 6 1 2 9 3 8 2樣例輸出 解題思路利用快速排序找到主元的位置,判斷主元是第幾小的 主元位置大了剪掉右邊的 主元位置小了剪掉左邊的 假設要找第三小的數...

求陣列中第K大的數

本題的的陣列是可以包含重複元素的,且要求時間複雜度控制在o n 解題思路 陣列中第k大的數等價於排序陣列中第n k個數,直觀的想法是將陣列排序後取第n k個數即可,但是最快的排序演算法時間複雜度也是o nlogn 可以參考快速排序一次劃分的思想,將時間複雜度降低為o n 一次劃分可以講陣列分為三部分...