題目描述
給定一個大小為 n 的數組,找到其中的眾數。眾數是指在數組中出現次數大於 ⌊ n/2 ⌋ 的元素。
你可以假設數組是非空的,並且給定的數組總是存在眾數。
示例 1:
輸入: [3,2,3]
輸出: 3
示例 2:
輸入: [2,2,1,1,1,2,2]
輸出: 2
思路
思路一:
利用哈希表的映射,儲存數組中的數字以及它們出現的次數,當眾數出現時,返回這個數字。
思路二:
因為眾數是出現次數大於n/2的數字,所以排序之后中間的那個數字一定是眾數。即nums[n/2]為眾數。但是在計算比較大的數組時,時間會超過限制。
思路三:
分治法,將整個數組分成兩個部分,先分別篩選出這兩部分中出現次數最多的數,記為left和right,如果left等於right,則返回left,如果left不等於right,則left和right都是最終結果的候選,此時需要遍歷整個數組考察left和right出現的次數,出現次數較多的就是最終返回的結果。
思路四:
摩爾投票算法,先將第一個數字假設為眾數,然后把計數器設為1,比較下一個數和此數是否相等,若相等則計數器加一,反之減一。然后看此時計數器的值,若為零,則將當前值設為候選眾數。以此類推直到遍歷完整個數組,當前候選眾數即為該數組的眾數。
代碼實現
package Array;
import java.util.HashMap;
/**
* 169. Majority Element(求眾數)
* 給定一個大小為 n 的數組,找到其中的眾數。眾數是指在數組中出現次數大於 ⌊ n/2 ⌋ 的元素。
* 你可以假設數組是非空的,並且給定的數組總是存在眾數。
*/
public class Solution169 {
public static void main(String[] args) {
Solution169 solution169 = new Solution169();
int[] nums = new int[]{3, 2, 3};
System.out.println(solution169.majorityElement_4(nums));
}
/**
* 利用哈希表的映射,儲存數組中的數字以及它們出現的次數,當眾數出現時,返回這個數字。
*
* @param nums
* @return
*/
public int majorityElement(int[] nums) {
HashMap<Integer, Integer> map = new HashMap<>();
for (int num :
nums) {
Integer cnt = map.get(num);
if (cnt == null) {
cnt = 1;
} else {
cnt++;
}
if (cnt > nums.length / 2) {
return num;
}
map.put(num, cnt);
}
return 0;
}
/**
* 因為眾數是出現次數大於n/2的數字,所以排序之后中間的那個數字一定是眾數。即nums[n/2]為眾數。但是在計算比較大的數組時,時間會超過限制。
*
* @param nums
* @return
*/
public int majorityElement_2(int[] nums) {
int n = nums.length;
for (int i = 0; i < n - 1; i++) {
for (int j = 0; j < n - 1 - i; j++) {
if (nums[j] > nums[j + 1]) {
int temp = nums[j];
nums[j] = nums[j + 1];
nums[j + 1] = temp;
}
}
}
return nums[n / 2];
}
/**
* 分治法,將整個數組分成兩個部分,先分別篩選出這兩部分中出現次數最多的數,記為left和right,如果left等於right,則返回left
* 如果left不等於right,則left和right都是最終結果的候選,此時需要遍歷整個數組考察left和right出現的次數,出現次數較多的就是最終返回的結果。
*
* @param nums
* @return
*/
public int majorityElement_3(int[] nums) {
return find(nums, 0, nums.length - 1);
}
public int find(int[] nums, int begin, int end) {
if (begin == end) {
return nums[begin];
} else {
int mid = (begin + end) / 2;
int left = find(nums, begin, mid);
int right = find(nums, mid + 1, end);
//左右兩部分的眾數相同 則這個數是這部分的眾數
if (left == right) {
return left;
} else {
//左右兩部分的眾數不相同 則這兩個數都有可能是這部分的眾數,那么遍歷這個數組,看一下哪個數字的出現次數多
int countLeft = 0;
int countRight = 0;
for (int i = begin; i <= end; i++) {
if (nums[i] == left) {
countLeft++;
} else if (nums[i] == right) {
countRight++;
}
}
if (countLeft > countRight) {
return left;
} else {
return right;
}
}
}
}
/**
* 摩爾投票算法,先將第一個數字假設為眾數,然后把計數器設為1,比較下一個數和此數是否相等,若相等則計數器加一,反之減一。
* 然后看此時計數器的值,若為零,則將當前值設為候選眾數。以此類推直到遍歷完整個數組,當前候選眾數即為該數組的眾數。
*
* @param nums
* @return
*/
public int majorityElement_4(int[] nums) {
int maj = nums[0];
int count = 1;
for (int num : nums) {
if (maj == num) {
count++;
} else {
count--;
if (count == 0) {
maj = num;
count = 1;
}
}
}
return maj;
}
}