## Wednesday, November 25, 2015

### LintCode - Majority Number III

http://blog.welkinlan.com/2015/05/29/majority-number-lintcode-java/
Given an array of integers and a number k, the majority number is the number that occurs `more than 1/k` of the size of the array.
Find it.
Example
Given `[3,1,2,3,2,3,3,4,4,4]` and `k=3`, return `3`.
Note
There is only one majority number in the array.
O(n) time and O(k) extra space
Same as above, As there could be at most (k – 1) elements occuring more than 1 / k of the array, we have (k – 1) slots for majority number candidates. The voting rule is the same as above.
Careful for the ConcurrentModificationException in HashMap, we should remove (write) the keys during the HashMap being iterated (read). Write the hashmap after read.

public int majorityNumber(ArrayList<Integer> nums, int k) {
if (nums == null || nums.size() == 0) {
return -1;
}
HashMap<Integer, Integer> map = new HashMap<Integer, Integer>();
for (int n : nums) {
if (!map.containsKey(n)) {
if (map.size() > k - 1) {
//if all slots occupied, vote negative to all elements
voteNegative(map);
} else {
//get an available slot and vote positive
map.put(n, 1);
}
} else {
//vote positive
map.put(n, map.get(n) + 1);
}
}
int maxKey = 0;
int maxCount = 0; // seems not right, have to recount
for (int key : map.keySet()) {
if (map.get(key) > maxCount) {
maxCount = map.get(key);
maxKey = key;
}
}
return maxKey;
}

private void voteNegative(Map<Integer, Integer> map) {
Set<Integer> keySet = map.keySet();
List<Integer> removeList = new ArrayList<>(); // use iterator
for (Integer key : keySet) {
if (map.get(key) == 1) {
}
else {
map.put(key, map.get(key) - 1);
}
}
//remove candidates with 0 votes and free the slot
for (Integer key : removeList) {
map.remove(key);
}
}
http://algorithm.yuanbin.me/zh-cn/math_and_bit_manipulation/majority_number_iii.html
``````    public int majorityNumber(ArrayList<Integer> nums, int k) {
HashMap<Integer, Integer> hash = new HashMap<Integer, Integer>();
if (nums == null || nums.isEmpty()) return -1;

// update HashMap
for (int num : nums) {
if (!hash.containsKey(num)) {
hash.put(num, 1);
if (hash.size() >= k) {
removeZeroCount(hash);
}
} else {
hash.put(num, hash.get(num) + 1);
}
}

// reset
for (int key : hash.keySet()) {
hash.put(key, 0);
}
for (int key : nums) {
if (hash.containsKey(key)) { // we can get max value at same time.
hash.put(key, hash.get(key) + 1);
}
}

// find max
int maxKey = -1, maxCount = 0;
for (int key : hash.keySet()) {
if (hash.get(key) > maxCount) {
maxKey = key;
maxCount = hash.get(key);
}
}

return maxKey;
}

private void removeZeroCount(HashMap<Integer, Integer> hash) {
Set<Integer> keySet = hash.keySet();
for (int key : keySet) {
hash.put(key, hash.get(key) - 1);
}

/* solution 1 */
Iterator<Map.Entry<Integer, Integer>> it = hash.entrySet().iterator();
while (it.hasNext()) {
Map.Entry<Integer, Integer> entry = it.next();
if(entry.getValue() == 0) {
it.remove();
}
}

/* solution 2 */
// List<Integer> removeList = new ArrayList<>();
// for (int key : keySet) {
//     hash.put(key, hash.get(key) - 1);
//     if (hash.get(key) == 0) {
//     }
// }
// for (Integer key : removeList) {
//     hash.remove(key);
// }

/* solution3 lambda expression for Java8 */
}
}``````
http://www.jiuzhang.com/solutions/majority-number-iii/
```    public int majorityNumber(ArrayList<Integer> nums, int k) {
// count at most k keys.
HashMap<Integer, Integer> counters = new HashMap<Integer, Integer>();
for (Integer i : nums) {
if (!counters.containsKey(i)) {
counters.put(i, 1);
} else {
counters.put(i, counters.get(i) + 1);
}

if (counters.size() >= k) {
removeKey(counters);
}
}

// corner case
if (counters.size() == 0) {
return Integer.MIN_VALUE;
}

// recalculate counters
for (Integer i : counters.keySet()) {
counters.put(i, 0);
}
for (Integer i : nums) {
if (counters.containsKey(i)) {
counters.put(i, counters.get(i) + 1);
}
}

// find the max key
int maxCounter = 0, maxKey = 0;
for (Integer i : counters.keySet()) {
if (counters.get(i) > maxCounter) {
maxCounter = counters.get(i);
maxKey = i;
}
}

return maxKey;
}

private void removeKey(HashMap<Integer, Integer> counters) {
Set<Integer> keySet = counters.keySet();
List<Integer> removeList = new ArrayList<>();
for (Integer key : keySet) {
counters.put(key, counters.get(key) - 1);
if (counters.get(key) == 0) {
}
}
for (Integer key : removeList) {
counters.remove(key);
}
}```
https://github.com/shawnfan/LintCode/blob/master/Java/Majority%20Number%20III.java
public int majorityNumber(ArrayList<Integer> nums, int k) {
if (nums == null || nums.size() == 0) {
return -1;
}
HashMap<Integer, Integer> map = new HashMap<Integer, Integer>();
for (Integer num : nums) {
if (map.containsKey(num)) {//Found duplicates, count++
map.put(num, map.get(num) + 1);
} else {
if (map.size() == k) {//All candidates added, do count--
Iterator<Map.Entry<Integer, Integer>> iter = map.entrySet().iterator();
while (iter.hasNext()) {
Map.Entry<Integer, Integer> entry = iter.next();
if (entry.getValue() - 1 == 0) {
iter.remove(); //
} else {
map.put(entry.getKey(), entry.getValue() - 1);
}
}//While
} else {
map.put(num, 1);
}
}
}//For

int result = 0;
int max = 0;
for (Map.Entry<Integer, Integer> entry : map.entrySet()) {
if (entry.getValue() > max) {
max = entry.getValue();
result = entry.getKey();
}
}
return result;
}
http://www.shuatiblog.com/blog/2014/06/28/Majority-Number-III/
This method is also used in counting highly-frequent string keywords. For example, another post [Design] Big Data – Real Time Top K discusses about it.
http://www.geeksforgeeks.org/given-an-array-of-of-size-n-finds-all-the-elements-that-appear-more-than-nk-times/
http://algorithms.tutorialhorizon.com/find-all-elements-in-an-array-which-appears-more-than-nk-times-n-is-array-size-and-k-is-a-number/