題目描述
數組中有一個數字出現的次數超過數組長度的一半,請找出這個數字。
你可以假設數組是非空的,並且給定的數組總是存在多數元素。
示例 1:
輸入: [1, 2, 3, 2, 2, 2, 5, 4, 2]
輸出: 2
限制:
1 <= 數組長度 <= 50000
自己的想法(比較low)
因爲用Java寫的,所以藉助的Map容器,正好也鞏固了下HashMap常用方法和遍歷方式。看了官方解法後…發現無論從空間還是時間是上說,才發現又更簡單的方法
class Solution {
public int majorityElement(int[] nums) {
if(nums.length == 1) return nums[0];
Map<Integer, Integer> map = new HashMap<Integer, Integer>();
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);
}
}
int res = 0;
for(Map.Entry<Integer, Integer> entry: map.entrySet()){
if(entry.getValue() > nums.length/2){
res = entry.getKey();
break;
}
}
return res;
}
}
官方解法(摩爾投票法)
很巧妙,使用投票法來解決
摩爾投票法:
票數和: 由於衆數出現的次數超過數組長度的一半;若記 衆數 的票數爲 +1 ,非衆數 的票數爲 -1 ,則一定有所有數字的 票數和 >0 。
票數正負抵消: 設數組 nums 中的衆數爲 x ,數組長度爲 n 。若 nums 的前 a 個數字的 票數和 = 0 ,則 數組後 (n−a) 個數字的 票數和一定仍>0 (即後 (n−a) 個數字的 衆數仍爲 x )
算法原理
爲構建正負抵消,假設數組首個元素 n1爲衆數,遍歷統計票數,當發生正負抵消時,剩餘數組的衆數一定不變 ,這是因爲(設真正的衆數爲 x )
- 當 n1=x 時: 抵消的所有數字中,有一半是衆數 x 。
- 當 n1!=x時: 抵消的所有數字中,少於或等於一半是衆數 xx
利用此特性,每輪假設都可以 縮小剩餘數組區間 。當遍歷完成時,最後一輪假設的數字即爲衆數(由於衆數超過一半,最後一輪的票數和必爲正數)
class Solution {
public int majorityElement(int[] nums) {
int candidate = nums[0];
int count = 1;
for (int i = 1;i < nums.length;i ++) {
if (nums[i] == candidate) {
count++;
}
else {
if (count == 0) {
candidate = nums[i];
}
else {
count--;
}
}
}
return candidate;
}
}
收穫到了:
- 摩爾投票法。票數和: 由於衆數出現的次數超過數組長度的一半。
- HashMap基本用法及遍歷方式