java实现算法之MajorityElement

时间:2022-02-19 22:23:26

 Majority Element


Description:


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.


Approach1:

Intuition


We know that the majority element occurs more than n/2 times, and a HashMap allows us to count element occurrences efficiently.


Algorithm

We can use a HashMap that maps elements to counts in order to count occurrences in linear time by looping over nums. Then, we simply return the key with maximum value.

public static int findMajorityElement1(int []a) {
int length=a.length;
HashMap<Integer,Integer>map=new HashMap<Integer,Integer>();
for(int i=0;i<length;i++) {
if(map.containsKey(a[i])) {
map.put(a[i],map.get(a[i])+1);
}else {
map.put(a[i], 1);
}
}
for(int i=0;i<length;i++) {
if(map.get(a[i])>length/2) {
return a[i];
}
}
return -1;
}


时间复杂度:O(n)

空间复杂度:O(n)

Approach2:

Intuition

If we had some way of counting instances of the majority element as +1+1 and instances of any other element as -1−1, summing them would make it obvious that the majority element is indeed the majority element.


Algorithm


Essentially, what Boyer-Moore does is look for a suffix sufsuf of nums where suf[0]suf[0] is the majority element in that suffix. To do this, we maintain a count, which is incremented whenever we see an instance of our current candidate for majority element and decremented whenever we see anything else. Whenever count equals 0, we effectively forget about everything in nums up to the current index and consider the current number as the candidate for majority element. It is not immediately obvious why we can get away with forgetting prefixes of nums - consider the following examples (pipes are inserted to separate runs of nonzero count).


[7, 7, 5, 7, 5, 1 | 5, 7 | 5, 5, 7, 7 | 7, 7, 7, 7]


Here, the 7 at index 0 is selected to be the first candidate for majority element. count will eventually reach 0 after index 5 is processed, so the 5 at index 6 will be the next candidate. In this case, 7 is the true majority element, so by disregarding this prefix, we are ignoring an equal number of majority and minority elements - therefore, 7 will still be the majority element in the suffix formed by throwing away the first prefix.


[7, 7, 5, 7, 5, 1 | 5, 7 | 5, 5, 7, 7 | 5, 5, 5, 5]


Now, the majority element is 5 (we changed the last run of the array from 7s to 5s), but our first candidate is still 7. In this case, our candidate is not the true majority element, but we still cannot discard more majority elements than minority elements (this would imply that count could reach -1 before we reassign candidate, which is obviously false).


Therefore, given that it is impossible (in both cases) to discard more majority elements than minority elements, we are safe in discarding the prefix and attempting to recursively solve the majority element problem for the suffix. Eventually, a suffix will be found for which count does not hit 0, and the majority element of that suffix will necessarily be the same as the majority element of the overall array.


public int majorityElement(int[] nums) {
int count = 0;
Integer candidate = null;

for (int num : nums) {
if (count == 0) {
candidate = num;
}
count += (num == candidate) ? 1 : -1;
}

return candidate;
}

时间复杂度:O(N)

空间复杂度:O(1)