尋找多數元素這一問題主要運用了:Majority Vote Alogrithm(最大投票算法)
1.Majority Element
1)description
Given an array of size n, find the majority element. The majority element is the element that appears more than ⌊ n/2 ⌋
times.
You may assume that the array is non-empty and the majority element always exist in the array.
注意3點:這里的多數元素必須嚴格大於⌊ n/2 ⌋(向下取整)、題目假定數組非空、假定最大元素一定存在(並且我們可以知道滿足要求的元素僅1個)。
eg:[1,2,7,2,2,5,10,2,2] n=9 最多數元素為2,因為它出現次數為5>⌊ 9/2 ⌋=4.
鏈接中有leetcoder的六種方案,例如最直觀的哈希表:map遍歷時通過對相同數組元素逐一累加可以篩選出滿足條件的元素,這一方案對Majority Element II也適用;或者通過對數組先排序,那么取出數組索引為⌊ n/2 ⌋的元素即可;又有隨機抽取數組中的元素然后求其出現次數,由於最多數元素為⌊ n/2 ⌋個,所以最糟情況下猜了⌊ n/2 ⌋次;分治法;最大投票算法。
3)最大投票算法原理:
遍歷數組,當碰到兩個不一樣的數字時,將這兩個數字同時丟棄,這兩個數字中可能有一個為 Majority Element,也可能兩個都不為Majority Element.因為k
大於 n/2
,所以在最差情況下(每次移除不同數字時都包含一個Majority Element),我們仍然能夠保證最后得到的數字是Majority Element.總之:在原序列中去除兩個不同的元素后,在原序列中的多數元素在新序列中還是多數元素。
根據《算法設計技巧與分析》書中的算法可以寫出如下非遞歸代碼(書中為遞歸版本並且附有檢查候選的最多數元素是否存在):
class Solution { public: int majorityElement(vector<int>& nums) { int j,candidate,count; //candidate代表候選解即最多數元素,count代表票數 for (j = 0; j < nums.size(); j++){ candidate = nums[j]; count = 1; //起初假定第一個元素即為candidate且票數為1,當票數count=0時就換candidate while (j < nums.size() - 1 && count>0){ j = j + 1; if (nums[j] == candidate) count++; //當下一個元素與candidate相等時票數+1 else count--; //否則票數-1 } } return c; } };
下面代碼和上面完全一樣,只是更直觀一點:
class Solution { public: int majorityElement(vector<int>& nums) { int candidate, count = 0, n = nums.size(); for (int i = 0; i < n; i++) { if (count==0) { //票數為0則換candidate,換了candidate票數就得變為1 candidate = nums[i]; count = 1; } else if(nums[i] == candidate) //下一個元素和candidate相等時票數+1 count++; else count--; //不相等票數-1 } return candidate; } };
總結:因為數組個數為n,且最多數元素個數>⌊ n/2 ⌋,所以有且只有1個元素滿足條件,所以設置了一個candidate和一個計票器count。而 Majority Element II要求是最多數元素個數>⌊ n/3 ⌋,所以至多有2個元素滿足要求,所以需要設置兩個candidate和兩個計票器count。
2.Majority Element II
1)description:Given an integer array of size n, find all elements that appear more than ⌊ n/3 ⌋
times. The algorithm should run in linear time and in O(1) space.
2)思路:我們需要找到三個不同的數字,然后拋棄掉這三個數字:首先要判斷是否等於candidate
,如果等於candidate
那么對應的 candidate
必須加一等待其他的數字來消除它,當有一個 candidate
的 count
為 0 時,說明該 candidate
已經全部被消除,我們需要設定新的 candidate
數字。當一個數字不等於兩個 candidate
,同時兩個 candidate
的 count
都不為零。這意味着當前這個數字就是這兩個candidate
等待的第三個數字。於是這三個數字被移除,同時它們的的 count
都要減一。
eg:[2,1,1,4,6,1,10] n=7 元素1的個數為3>⌊ 7/3 ⌋=2
[2,1,1,1,10,2,2,1] n=8 元素1個數為4>⌊ 8/3 ⌋=2,元素2的個數為3>⌊ 8/3 ⌋=2
python代碼:
class Solution(object): def majorityElement(self, nums): """ :type nums: List[int] :rtype: List[int] """ if not nums: return [] count1, count2, candidate1, candidate2 = 0, 0, 0, 0 //初始化兩個candidate和兩個count
for n in nums: if n == candidate1: //注意這里的元素值相等和count為0的判斷順序與問題一中正好相反 count1 += 1 //這里先判斷元素值與candidate是否相等 elif n == candidate2: count2 += 1 elif count1 == 0: //再判斷count是否為0 candidate1, count1 = n, 1 elif count2 == 0: candidate2, count2 = n, 1
else: count1, count2 = count1 - 1, count2 - 1
return [n for n in (candidate1, candidate2) if nums.count(n) > len(nums) // 3]
參考:segmentFault