169.Majority Element
题意:
Given an array of size n, find the majority element. The majority element is the element that appears more than ⌊ n/2 ⌋ times.
You may assume that the array is non-empty and the majority element always exist in the array.
给定一个长度为 n 的数组,找出 majority元素,majority元素是指出现次数超过 ⌊n/2⌋ 次的元素。
我的思路:
数组元素重复问题,想到用 HashMap,利用 key 表示数组元素,value 表示该数组元素出现的次数,只要次数大于数组长度的一半就可返回该元素。
这道题之所以可以这样做,是因为有假设条件,
* 假设1:非空数组;
* 假设2:大多数元素总是存在;所以不会出现输入为 [1,2,3,4,5,6] 这种情况;
这题的代码中最后的 return -1;永远不会执行。
public int majorityElement(int[] nums) {
Map<Integer, Integer> map = new HashMap<>();
int length = nums.length;
for(int i = 0; i < length; i++){
if(map.containsKey(nums[i])){
int val = map.get(nums[i]);
if(val + 1 > length / 2){
return nums[i];
}
map.put(nums[i], val + 1);
}else{
map.put(nums[i], 1);
if(1 > length / 2){
return nums[i];
}
}
}
return -1;
}
答案:方法一:
这种方法思路和我的思路是一样的,都是用的 HashMap;
但是他多做了一步,就是把遍历完数组的所有元素,然后将数组的所有元素及元素个数放在 Map 中;然后遍历这个 Map ,返回 Map 中 value 值最大的 key 。
时间复杂度:O(n)
空间复杂度:O(n)
public int majorityElement2(int[] nums) {
Map<Integer, Integer> counts = countNums(nums);
Map.Entry<Integer, Integer> majorityEntry = null;
for (Map.Entry<Integer, Integer> entry : counts.entrySet()) {
if (majorityEntry == null || entry.getValue() > majorityEntry.getValue()) {
majorityEntry = entry;
}
}
return majorityEntry.getKey();
}
private Map<Integer, Integer> countNums(int[] nums) {
Map<Integer, Integer> counts = new HashMap<Integer, Integer>();
for (int num : nums) {
if (!counts.containsKey(num)) {
counts.put(num, 1);
}
else {
counts.put(num, counts.get(num)+1);
}
}
return counts;
}
答案:方法二:
新的思路2,这种思路真是巧妙。
这种思路也是基于这道题的假设,假设1:数组非空;假设2:数组中一定存在一个大多数元素。
那么我们先将这个数组进行排序,发现,不论数组的长度为偶数还是奇数,大多数元素都会出现在 length/2 的位置 。
public int majorityElement3(int[] nums) {
Arrays.sort(nums);
return nums[nums.length/2];
}
答案:方法三:
新的思路3,因为这个数组中有一多半都是我们要找的元素,那么如果我们在数组中随机取一个元素,
那么这个元素就是我们要找的元素的概率很大。
但是这种方法的时间复杂度在最坏的情况下是无穷,只是提供这种思路;
空间复杂度就是O(1)
public int majorityElement4(int[] nums) {
Random rand = new Random();
int majorityCount = nums.length/2;
while (true) {
int candidate = nums[randRange(rand, 0, nums.length)];
if (countOccurences(nums, candidate) > majorityCount) {
return candidate;
}
}
}
private int randRange(Random rand, int min, int max) {
return rand.nextInt(max - min) + min;
}
private int countOccurences(int[] nums, int num) {
int count = 0;
for (int i = 0; i < nums.length; i++) {
if (nums[i] == num) {
count++;
}
}
return count;
}
答案:方法四:
新的思路4,分而治之的思想 Divide and Conquer [Accepted]
自己没有看懂
* 时间复杂度:O(nlgn)
* 空间复杂度:O(lgn)
public int majorityElement5(int[] nums) {
return majorityElementRec(nums, 0, nums.length-1);
}
private int majorityElementRec(int[] nums, int lo, int hi) {
// base case; the only element in an array of size 1 is the majority
// element.
if (lo == hi) {
return nums[lo];
}
// recurse on left and right halves of this slice.
int mid = (hi-lo)/2 + lo;
int left = majorityElementRec(nums, lo, mid);
int right = majorityElementRec(nums, mid+1, hi);
// if the two halves agree on the majority element, return it.
if (left == right) {
return left;
}
// otherwise, count each element and return the "winner".
int leftCount = countInRange(nums, left, lo, hi);
int rightCount = countInRange(nums, right, lo, hi);
return leftCount > rightCount ? left : right;
}
private int countInRange(int[] nums, int num, int lo, int hi) {
int count = 0;
for (int i = lo; i <= hi; i++) {
if (nums[i] == num) {
count++;
}
}
return count;
}
答案:方法五:Boyer-Moore投票算法
这种算法正确的前提是:大多数元素个数超过数组长度的一半。
不同的数之间相互抵消。
public int majorityElement6(int[] nums){
int count = 0;
Integer maj = null;
for (int i : nums) {
if(count == 0){
maj = i;
}
count += maj == i ? 1 : -1;
}
return maj;
}