Given an array of size n, find the majority element. The majority element is the element that appears more than ⌊ n/2 ⌋
times.html
You may assume that the array is non-empty and the majority element always exist in the array.git
Example 1:github
Input: [3,2,3] Output: 3
Example 2:算法
Input: [2,2,1,1,1,2,2] Output: 2
這是到求大多數的問題,有不少種解法,其中我感受比較好的有兩種,一種是用哈希表,這種方法須要 O(n) 的時間和空間,另外一種是用一種叫摩爾投票法 Moore Voting,須要 O(n) 的時間和 O(1) 的空間,比前一種方法更好。這種投票法先將第一個數字假設爲過半數,而後把計數器設爲1,比較下一個數和此數是否相等,若相等則計數器加一,反之減一。而後看此時計數器的值,若爲零,則將下一個值設爲候選過半數。以此類推直到遍歷完整個數組,當前候選過半數即爲該數組的過半數。不仔細弄懂摩爾投票法的精髓的話,過一陣子仍是會忘記的,首先要明確的是這個叼炸天的方法是有前提的,就是數組中必定要有過半數的存在才能使用,下面來看本算法的思路,這是一種先假設候選者,而後再進行驗證的算法。現將數組中的第一個數假設爲過半數,而後進行統計其出現的次數,若是遇到一樣的數,則計數器自增1,不然計數器自減1,若是計數器減到了0,則更換下一個數字爲候選者。這是一個很巧妙的設定,也是本算法的精髓所在,爲啥遇到不一樣的要計數器減1呢,爲啥減到0了又要更換候選者呢?首先是有那個強大的前提存在,必定會有一個出現超過半數的數字存在,那麼若是計數器減到0了話,說明目前不是候選者數字的個數已經跟候選者的出現個數相同了,那麼這個候選者已經很 weak,不必定能出現超過半數,此時選擇更換當前的候選者。那有可能你會有疑問,那萬一後面又大量的出現了以前的候選者怎麼辦,不須要擔憂,若是以前的候選者在後面大量出現的話,其又會從新變爲候選者,直到最終驗證成爲正確的過半數,佩服算法的提出者啊,代碼以下:數組
C++ 解法一:app
class Solution { public: int majorityElement(vector<int>& nums) { int res = 0, cnt = 0; for (int num : nums) { if (cnt == 0) {res = num; ++cnt;} else (num == res) ? ++cnt : --cnt; } return res; } };
Java 解法一:post
public class Solution { public int majorityElement(int[] nums) { int res = 0, cnt = 0; for (int num : nums) { if (cnt == 0) {res = num; ++cnt;} else if (num == res) ++cnt; else --cnt; } return res; } }
下面這種解法利用到了位操做 Bit Manipulation 來解,將這個大多數按位來創建,從0到31位,每次統計下數組中該位上0和1的個數,若是1多,那麼將結果 res 中該位變爲1,最後累加出來的 res 就是過半數了,至關讚的方法,參見代碼以下:url
C++ 解法二:spa
class Solution { public: int majorityElement(vector<int>& nums) { int res = 0, n = nums.size(); for (int i = 0; i < 32; ++i) { int ones = 0, zeros = 0; for (int num : nums) { if (ones > n / 2 || zeros > n / 2) break; if ((num & (1 << i)) != 0) ++ones; else ++zeros; } if (ones > zeros) res |= (1 << i); } return res; } };
Java 解法二:code
public class Solution { public int majorityElement(int[] nums) { int res = 0, n = nums.length; for (int i = 0; i < 32; ++i) { int ones = 0, zeros = 0; for (int num : nums) { if (ones > n / 2 || zeros > n / 2) break; if ((num & (1 << i)) != 0) ++ones; else ++zeros; } if (ones > zeros) res |= (1 << i); } return res; } }
Github 同步地址:
https://github.com/grandyang/leetcode/issues/169
相似題目:
參考資料:
https://leetcode.com/problems/majority-element/
https://leetcode.com/problems/majority-element/discuss/51613/O(n)-time-O(1)-space-fastest-solution