主元素(majority number)定義為陣列中出現次數嚴格超過一半的數。找到這個數。要求使用o(1)的額外空間和o(n)的時間。
初階:有n個數,其中乙個數的出現次數嚴格超過了一半。求這個數。
高階1:有n個數,其中兩個數的出現次數都超過了⅓ ,求這兩個數。
高階2:有n個數,其中乙個數的出現次數嚴格超過了⅓,並且沒有第二個這樣的數。求這個數
高階3:
如果陣列中存在且只存在乙個出現次數嚴格超過1/k的數,找到這個數。要求使用o(k)的額外空間和o(n)的時間
。初階:
採用抵消法。一旦發現陣列中存在兩個不同的數,就都刪除,直到剩下的數都一樣。此時剩下的數就是主元素。因為每次抵消操作之 後,剩下來的數種,主元素一定也還是超過一半的。具體實現的時候,記錄乙個candidate和其出現的次數count,遍歷每個數,如果count==0,則把candidate置為遍歷到的數,否則看遍歷到的數和candidate是否相等,如果相等,則count++,否則count--(抵消),遍歷結束後,candidate就是主元素。c++實現如下:
int majorityelement2(vector& nums)
高階1:仍然是抵消法。如果三個數不一樣,就三個數都扔掉。因此記錄2個數,及其各自出現次數即可。直接上**:
vectormajorityelement(vector& nums)
else if (cnt2 == 0) else
}int count1=0,count2=0,tmp=0;
for(int i=0;in/3)
res.push_back(tmp1);
if(count2>n/3)
res.push_back(tmp2);
return res;
}
高階2:該問題其實是高階1的簡化版,可直接通過修改高階1**實現
int majorityelement(vector& nums)
else if (cnt2 == 0) else
}int count1=0,count2=0,tmp=0;
for(int i=0;icount2)return tmp1;
else return tmp2;
}
高階3:乙個方法是按照前面的進行推廣,如果出現k個不一樣的數,就抵消掉。假設k=4,實現如下
int majorityelement4(vector& nums)
else if (cnt2 == 0) else if (cnt2 == 0) else
}int count1=0,count2=0,count3=0;
for(int i=0;imymap;
mymap.insert(pair(count1, tmp1));
mymap.insert(pair(count2, tmp2));
mymap.insert(pair(count3, t***));
map::iterator iter = mymap.find(c);
return iter->second;
}
高階3:另乙個思路是,如果出現k個不一樣的數,就抵消掉。這裡需要用巧妙的資料結構來記錄candidates,並使得如下操作均為o(1):
1. 加入乙個candidate/給某個candidate出現次數+1
2. candidates中是否存在某個數
3. candidates中所有數的出現次數 - 1
4. 移除出現次數為0的candidates
對於1,2兩個操作,我們自然可以想到使用hash表來完成。對於第4兩個操作,我們希望能夠有出現次數最少的candidate的資訊,但是如果使用heap則並非o(1)的時間複雜度。注意到每一次加入乙個candidate時,count均為1,每一次給改變乙個candidate出現次數時,也只涉及到加1運算。因此,如果我們能維護candidates的有序性,就可以容易的解決這個問題。方法是,使用linkedlist。與普通的linkedlist不同的是,我們將所有出現次數相同的candidate放在乙個bucket裡,bucket內部的candidate用doubly linked list鏈結起來,bucket之間也用doubly linked list鏈結起來。這樣針對+1運算,我們只需要通過hash表找到對應的candidate,把candidate從當前的bucket移動到下乙個bucket(出現次數+1的bucket)。另外,對於所有數-1的操作,我們記錄全域性的乙個base,每次-1操作,則base+1。如果base和buckets中的第乙個bucket中的candidates的出現次數相同,則整個刪除第乙個bucket。最後,我們會得到最大k-1個candidates,重新遍歷一遍整個陣列,用o(k)的hash記錄這k-1個candidates的出現次數,就可以驗證誰是真正的主元素。
**************************c++實現下次更新*************************
完整的測試**:
#include#include#includeusing namespace std;
vectormajorityelement(vector& nums)
else if (cnt2 == 0) else
}int count1=0,count2=0,tmp=0;
for(int i=0;in/3)
res.push_back(tmp1);
if(count2>n/3)
res.push_back(tmp2);
return res;
}int majorityelement2(vector& nums)
else if (cnt2 == 0) else
}int count1=0,count2=0,tmp=0;
for(int i=0;icount2)
return tmp1;
else return tmp2;
}int majorityelement4(vector& nums)
else if (cnt2 == 0) else if (cnt2 == 0) else
}int count1=0,count2=0,count3=0;
for(int i=0;imymap;
mymap.insert(pair(count1, tmp1));
mymap.insert(pair(count2, tmp2));
mymap.insert(pair(count3, t***));
map::iterator iter = mymap.find(c);
return iter->second;
}int main()
; int arr3=;
int arr=;
vectorvec2(arr2,arr2+7);
vectorvec3(arr3,arr3+4);
vectorvec(arr,arr+10);
vectorresult;
int a,b,c;
a = majorityelement2(vec2);
b = majorityelement3(vec3);
c = majorityelement4(vec3);
result = majorityelement(vec);
cout<<"出現1/2次以上的數:"<::iterator iter=result.begin();iter !=result.end();++iter)
cout<<*iter<<" ";
cout<
參考
主元素問題
設a是含有n個元素的陣列,如果元素x在a中出現的次數大於n 2,則稱x是a的主元素。給出乙個演算法,判斷a中是否存在主元素。因為主元素的個數大於n 2,如果兩個不同的元素兩兩抵消,最後若完全抵消,那麼就不存在主元素 若沒有完全抵消,那麼餘下的元素可能就是主元素,因此統計該元素的出現次數,即可判定是否...
主元素問題
主元素問題歡迎來到二陽的學習課堂,咱們先看一看問題描述 1.問題分析 當長度為n的序列a 現次數大於n 2的元素,則此元素為主元素。設主元素出現k次,則其他元素出現次數為n k 二者之差為c 2k n 但c 0時,主元素成立。2.演算法設計 從序列a前端開始遍歷,初始化主元素a a 0 計算遍歷過程...
主元素問題 Majority Element
2018 09 23 13 25 40 主元素問題是乙個非常經典的問題,一般來說,主元素問題指的是陣列中元素個數大於一半的數字,顯然這個問題可以通過遍歷計數解決,時間複雜度為o n 空間複雜度為o n 這樣的演算法有兩個弊端,一是空間複雜度較高,二是沒法處理資料流問題。因此就有了boyer moor...