169. 多數元素
知識點:陣列;排序;消消樂;分治;
題目描述
給定一個大小為 n 的陣列,找到其中的多數元素。多數元素是指在陣列中出現次數 大於 ⌊ n/2 ⌋ 的元素。
你可以假設陣列是非空的,並且給定的陣列總是存在多數元素。
示例
輸入:[3,2,3]
輸出:3
輸入:[2,2,1,1,1,2,2]
輸出:2
解法一:排序
因為這道題中說了一定有一個數字是大於一半的,所以可以直接將陣列進行排序,然後中間那個數一定是出現超過一半的。
class Solution {
public int majorityElement(int[] nums) {
if(nums.length == 1) return nums[0];
Arrays.sort(nums);
return nums[nums.length/2];
}
}
解法二:消消樂(投票法)
一定有一個數字超過一半,所以如果兩個不同的數字兩兩抵消的話最後留下來的那個一定就是出現次數超過一半的。先選最開始的作為候選人,然後count=1, 如果後面遇到一樣的,count++,遇到不一樣的,count--,count一旦到0以後,那就需要換新的候選人了。
class Solution {
public int majorityElement(int[] nums) {
int res = 0, count = 0;
for(int i = 0; i < nums.length; i++){
if(count == 0){
res = nums[i];
count++;
}else if(res == nums[i]){
count++;
}else if(res != nums[i]){
count--;
}
}
return res;
}
}
解法三:分治
如果有一個數字出現次數超過了一半,那將這個陣列分成兩半後,那這個數必定至少在其中一部分超過一半。
反證:如果這個數字在兩半里都沒超過一半,那在整個陣列裡必定也沒超過一半。所以可以分別求兩個子陣列裡超過一半的數字,然後選出兩個裡真正的出現最多的。
- 如果這兩個數字相同,那必定就是它了;
- 如果這兩個數字不同,統計兩個數字分別在陣列裡出現的次數,大的就是了;
class Solution {
public int majorityElement(int[] nums) {
return majorityElement(nums, 0, nums.length-1); //區間是左閉右閉;
}
private int majorityElement(int[] nums, int left, int right){
if(left == right){
return nums[left]; //結束條件;
}
int mid = left+((right-left) >> 1);
int leftnum = majorityElement(nums, left, mid); //左右兩側的超過一半的數字;
int rightnum = majorityElement(nums, mid+1, right);
if(leftnum == rightnum) return leftnum;
int leftcount = countNum(nums, leftnum, left, right); //比較兩個數字誰次數多;
int rightcount = countNum(nums, rightnum, left, right);
return leftcount > rightcount ? leftnum : rightnum;
}
private int countNum(int[] nums, int num, int left, int right){
int count = 0;
for(int i = left; i <= right; i++){
if(nums[i] == num){
count++;
}
}
return count;
}
}