Count with a map.O(n) time, O(n) space. Correct, obvious, and the
sensible default.
Sort and take the middle. A value occupying more than half the positions
must cover index n/2 whatever else is there. O(nlogn), one line, and a
nice argument.
Both are fine. The reason this problem is famous is a third answer that uses
no extra memory at all.
Boyer-Moore voting
Hold one candidate and one counter. Walk the array. Matching values vote for the
candidate, differing values vote against, and when the count hits zero the next
value becomes the new candidate.
▾ 20
21
12
13
14
25
26
candidate
2
count
1
The count had hit zero, so everything before this point cancelled out exactly. Whatever the
majority is, it is still the majority of what remains — so 2 becomes the new candidate.
funcmajorityElement(nums []int) int {
candidate :=0
count :=0
for _, v :=range nums {
if count ==0 {
candidate = v
}
if candidate == v {
count++
} else {
count--
}
}
return candidate
}
O(n) time, O(1) space, one pass.
The promise it depends on
Generalising to n/3
The same idea extends: at most two values can appear more than n/3 times,
so track two candidates and two counters. More than n/k needs k−1 of each —
the Misra–Gries algorithm, and Boyer-Moore is its k=2 case.
That generalisation is where it stops being a puzzle and starts being useful.
Finding heavy hitters in a stream — the IPs sending the most traffic, the
products bought most often — is exactly this, run over data far too large to
count exactly.