Majority Element asks you to find the value that appears more than half the time in an array. The clever solution, Boyer-Moore voting, finds it in one pass using just two variables — no extra memory at all.
Problem. Given an array nums of size n, return the majority element — the value that appears
more than n / 2 times. You may assume the majority element always exists.
Example: nums = [2, 2, 1, 1, 1, 2, 2] → answer 2 (it appears 4 times out of 7, and 4 > 7 / 2).
The slow way first
The obvious idea: count every value. Use a hash map from value to its frequency, scan once filling it in, then return whichever key has a count above n / 2. That works and it is O(n) time — but it costs O(n) extra space for the map.
The question to ask: can I find the winner without remembering every count? Because the majority element appears more than half the time, it outnumbers everything else combined. That imbalance is something we can exploit with a single counter.
The idea: let votes cancel out
Keep one candidate and a running count. Walk the array casting votes:
- If
countis 0, the candidate is up for grabs — adopt the current element and setcount = 1. - If the current element matches the candidate, it is a supporting vote:
count += 1. - If it differs, it is an opposing vote that cancels one:
count -= 1.
Pair off every minority element against a majority element and they annihilate each other. Since the majority element has more than half the votes, at least one of it always survives — whatever the candidate is at the end is the answer.
The key insight: we are not tracking the true count of any value — count just measures how far ahead the current candidate is. When it drops to 0 the lead is gone and a fresh candidate steps in.
Walk through it
Step through the animation. The pointer i scans left to right. Watch candidate and count underneath. Twice the count crashes to 0 and a new candidate is adopted (first 1, then back to 2), but 2 is the only value with enough votes to survive — so it wins. The final step verifies the survivor really appears more than half the time.
Pseudocode
candidate = none, count = 0
for each num in nums:
if count == 0:
candidate = num # empty seat — adopt this element
count = 1
else if num == candidate:
count = count + 1 # a supporting vote
else:
count = count - 1 # an opposing vote cancels one
return candidate # the survivor (majority is guaranteed)The Python solution
def majority_element(nums):
candidate = None
count = 0
for num in nums:
if count == 0:
candidate = num
count = 1
elif num == candidate:
count += 1
else:
count -= 1
# majority is guaranteed to exist
return candidatecandidateholds whoever is currently winning;countis their lead, not a true tally.- When
count == 0the lead has evaporated, so the currentnumclaims the seat and the lead resets to 1. elif num == candidateadds a supporting vote, raising the lead.- The
elsebranch is an opposing vote that cancels one unit of the lead. - After the loop,
candidateis the value that outlasted every cancellation — the majority element.
Complexity
| Case | Time | Notes |
|---|---|---|
| Hash-map counting | O(n) (moderate) | one pass, but O(n) space |
| Boyer-Moore (this solution) | O(n) (moderate) | one pass, O(1) space |
O(1) (fast)Both approaches are O(n) time, but Boyer-Moore wins on space: it uses just two variables instead of a whole map. That constant-space trick is what makes it a favorite interview answer.
When this pattern shows up
Reach for Boyer-Moore voting whenever a problem asks for an element that dominates the array — appears more than half (or more than a third) of the time. The core move is the same: let opposing items cancel and see who survives. The thirds version keeps two candidates and two counts.
The algorithm only guarantees a correct answer when a majority element actually exists. If the problem
does not promise one, add a second pass to verify the survivor really appears more than n / 2 times
before returning it.
Practice
For nums = [2, 2, 1, 1, 1, 2, 2], the count drops to 0 right before i reaches index 4. Which value gets adopted as the new candidate there?
1. What does the count variable actually represent?
2. What happens when count reaches 0?
3. Why does Boyer-Moore use O(1) space while hash-map counting uses O(n)?
4. When must you add a verification pass?