1. 程式人生 > >主元素,中位數以及快速排序問題(分治法問題)

主元素,中位數以及快速排序問題(分治法問題)

IBM最後有道求主元素的題目,一個數組有N個元素,其中有超過N/2的元素相同,請找出這個元素。時間複雜度為O(n)
方法1:
如果一個元素的個數超過N/2則這個元素必然是這N個元素的中位數。則這個題目是找中位數。方法是通過快速排序變化的來的演算法。
程式碼如下:
做這個題目複習了下快排,選擇一個pivot,然後圍繞這個pivot將陣列分成兩部分,左邊一部分的元素都小於pivot,右邊部分的元素都大於pivot,然後遞迴的處理左右兩個部分,直到陣列元素個數為1.找第k小元素的方法是基於快排的分割函式,將一個數組分割成兩部分。如果小於pivot的元素個數A小於k,則在分割後的陣列的右邊找第k-A小的元素,否則在左邊部分找。對於中位數就是第n/2小的數。根據演算法導論的說明,快排的平均演算法複雜度為O(nlogn),而找第k小元素的平均演算法複雜度為O(n)。找k小的演算法和快排的不同在於快排需要遞迴處理左邊和右邊兩個部分,即複雜度方程為: O(1) n = 1 T(n)={ 2T(n/2) n> 1而對於求第k小數,只需要遞迴處理一個分支,所以複雜度方程為: O(1) n = 1T(n)={ T(n/2) n> 1雖然只比快排少了個係數2,但是可以推匯出來求第k小數的複雜度為O(n),而快排為O(nlogn)方法2:求眾數的方法:
對於找主元素的題目,還有其他的做法,可以使用求眾數的方法,首先選擇一個pivot,然後將陣列分割成兩部分,左邊的小於pivot,右邊的大於pivot在分割過程中統計陣列中等於pivot的元素個數,小於pivot的元素個數以及大於pivot的元素個數。如果pivot的元素個數大於等於n/2,則pivot就是所求元素。如果小於pivot的元素個數大於等於n/2,則在左邊部分找,否在在右邊部分找。程式碼為:
在統計pivot出現次數時需要注意是在交換i,j對應元素時判斷的。因為只有當array[i]>=x並且array[j]<=x才需要交換元素。同時當退出While(i<j)時,需要判斷i==j&&Array[j]==pivot的情況,因為i==j的情況在while中是沒有處理的,所以必須在while外處理。當統計得到pivot的出現次數後可以進行遞迴。如pivot出現的次數大於等於n/2,則返回pivot,否在向元素個數大的那部分陣列遞迴。
方法3:主元素查詢:

關於這種主元素還有種更加巧妙地方法,沒看到過一定想不到的。這種方法的原理是如果一個數組中存在一個主元素(個數大於n/2),則同時刪除兩個不相等的值,這個主元素不會改變。
簡單的說就一個大小為n陣列中存在一個元素的個數大於n/2,則如果用這個陣列中其他元素和該主元素進行抵消的話,最後剩下的一定是主元素,因為主元素個數最多。
該方法可以在O(n)的時間內找到主元素,十分高效。
程式碼:

關鍵的演算法在找seed過程中,假設第一個元素是主元素,遍歷陣列,如果遇到和seed相同的元素則加1,不同則減1,如果count==0了,則seed改變。
該方法的基礎就是如果存在一個值是主元素,那麼遍歷一遍則出現的次數一定要大於其他所有元素的次數,所以最後主元素的count一定大於0.