題目描述:數組中有一個數字出現的次數超過數組長度的一半,請找出這個數字。
你可以假設數組是非空的,並且給定的數組總是存在多數元素。
示例 1:
輸入: [1, 2, 3, 2, 2, 2, 5, 4, 2]
輸出: 2
限制:
1 <= 數組長度 <= 50000
這道題目有多種解法
方法一:
哈希表統計法
建立哈希表統計nums中數字的數量,對應的數字爲鍵,鍵值爲數字的數量。當某一個數字的鍵值超過數組的一半長度時,該數字就是衆數。
class Solution{
public int majorityElement(int [] nums)
{
HashMap<Integer,Integer> map=new HashMap<>();
int length=nums.length/2;
for(int i=0;i<nums.length;i++)
{
if(map.containsKey(nums[i]))
{
map.put(nums[i],map.get(nums[i])+1);
}
else
{
map.put(nums[i],1);
}
if(map.get(nums[i])>length)
return nums[i];
}
return 0;
}
}
方法二:
數組排序法
利用效率較高的算法排序數組,例如快速歸併排序,堆排序,然後由於衆數的數量超過數組長度的一半,所以數組中點的元素一定就是衆數,算法的時間複雜度爲O(Nlog2N)
方法三:
摩爾投票法(這方法好稀奇)
首先定義幾個概念
- 票數和:由於衆數出現的次數超過數組長度的一半;若記衆數的票數爲+1,非衆數的票數爲-1,則一定有所有數字的票數和大於0
- 票數抵消:設置nums中的衆數爲x,數組長度爲n,若nums的前a個數字的票數和爲0,則數組後面n-a個數字的票數和一定大於0,也就是說後面n-a個數字中的衆數還是x。
算法原理:
-
爲構建正負抵消,假設數組中的首個元素n是衆數,遍歷統計票數,當發生正負抵消時,剩餘數組的衆數一定不變,因爲(設置真正的衆數爲x)
- 當n==x:抵消的所有數字中,有一半是衆數
- 當n!=x,抵消的所有數字中,少於等於一半是衆數
-
每輪假設都可以縮小剩餘數組的區間,遍歷結束,最後一輪假設的數字就是衆數。衆數超過一半,最後一輪的票數和必定爲正數
class Solution{
public int majorityElement(int [] nums){
int x=0,votes=0;
for(int num:nums){
if(votes==0)
x=num;
votes+=num==x? 1:-1;
}
return x;
}
}