隨機選擇演算法

2021-10-05 15:54:34 字數 2085 閱讀 1796

討論一種常見的演算法問題,topk問題,即從乙個無序陣列中求出第k大的數,比如陣列,第三大的數是5,第五大的數是9。

首先最簡單的方法是先排序,然後直接取出第k大元素,但是樣最好的時間複雜度也得到o(nlogn)。隨機選擇演算法可以到o(n)的複雜度。

原理有點類似於快速排序演算法,首先看一下快排中的randpartition函式:

int

ranpartition

(vector<

int> vec,

int left,

int right)

vec[left]

= temp;

return left;

}

對vec[left, right]執行一次randpartition函式之後,主元左側的元素個數就是確定的,且都小於主元。假設主元是vec[p],那麼vec[p]就是vec[left, right]中的第p - left + 1大的數。假設令m表示p - left + 1,那麼:

演算法left == right作為遞迴邊界,返回vev[left]:

int

randselect

(vector<

int> vec,

int left,

int right,

int k)

題目:給定乙個由整數組成的集合,集合中的整數各不相同,現在要將它分為兩個子集合,使得這兩個子集合的並為原集合、交為空集,同時在兩個子集合的元素個數n1和n2之差的絕對值|n1-n2|盡可能小的前提下,要求它們各自的元素之和s1與s2之差的絕對值|s1-s2|盡可能大。求這個|s1-s2|等於多少

一般思路:如果n是偶數,由它分出的兩個子集合中的元素個數都是n/2;當n是奇數時,由它分出的兩個子集合中的元素個數分別是n/2和n/2+1。為了讓|s1-s2|更大,最直接的思路是將原集合中的元素從小到大排序,取排序後的前n/2個元素作為其中乙個子集合,剩下乙個元素作為另乙個子集合,這樣時間複雜度是o(nlogn)

優化思路:使用上面的隨機選擇演算法。這個問題可以轉換為求原集合中元素的第n/2大,同時根據這個數把集合分為兩部分,此時也根本不需要排序,只要選出n/2大的數即可,此時時間複雜度為o(n)

#include

#include

#include

#include

using

namespace std;

intrandpartition

(vector<

int>&,

int,

int)

;void

randselect

(vector<

int>&,

int,

int,

int)

;int

main()

randselect

(vec,

0, n -

1, n /2)

;for

(int i =

0; i < n /

2; i++

) sum1 +

= vec[i]

; cout <<

(sum - sum1)

- sum1 << endl;

system

("pause");

return0;

}int

randpartition

(vector<

int>

& ans,

int left,

int right)

ans[left]

= temp;

return left;

}void

randselect

(vector<

int>

& ans,

int left,

int right,

int k)

輸出:1316

331840

105127

29380

隨機選擇演算法

問題描述 本文主要討論這樣乙個問題 如何從乙個無序的陣列中求出第k大的數。這個問題最直接的想法是對陣列排一下序,然後直接取出第k個元素即可,這樣做法需要o nlogn 的時間複雜度。這個方法比較簡單,在執行時間允許的情況下當然選這個方法 下面介紹隨機選擇演算法,它對任何輸入都可以達到o n 的期望時...

隨機選擇演算法

如何求解無序陣列中第k大的數?問題 將陣列劃分為兩個子集,元素個數分別為n1,n2,兩個子集各自元素之和分別為s1,s2,使 s2 s1 盡可能大,使 n1 n2 盡可能小。求 s2 s1 分析 僅尋找陣列中第n 2大的數,將陣列劃分為兩個集合,乙個子集的元素都小於這個數,另乙個子集的元素都大於這個...

隨機選擇演算法

問題描述 從乙個無序序列找乙個k大的數 最直接的想法是先排序再找,但這樣需要o nlogn 的時間複雜度 隨機選擇演算法雖然最壞的時間複雜度為o n 2 但對於任何輸入都可以達到o n 的時間複雜度 思想描述 選擇乙個主元,經過一次快排後主元為a p 在a left,right 中該主元為第p le...