Problem. Find the element appearing more than times in an array, if one exists.

Boyer-Moore voting — time, space

int majority(const vector<int>& a) {
    int cand = a[0], count = 0;
    for (int x : a) {
        if (count == 0) cand = x;
        count += (x == cand) ? 1 : -1;
    }
    // VERIFY — a majority may not exist
    int c = 0;
    for (int x : a) if (x == cand) c++;
    return c * 2 > (int)a.size() ? cand : -1;
}

The intuition: pair each occurrence of the candidate with a non-occurrence and cancel them. A true majority element survives every cancellation, because it has more copies than everything else combined.

Always verify

The algorithm returns some element even when no majority exists. The second pass is not optional. This is the most common mistake with this algorithm.

See Boyer-Moore Voting.

The generalisation: elements appearing more than times

At most such elements exist. Keep candidates with counts; when a new element matches none and all counters are non-zero, decrement all of them.

vector<int> majorityK(const vector<int>& a, int k) {
    map<int,int> cnt;                                  // at most k-1 entries
    for (int x : a) {
        if (cnt.count(x)) cnt[x]++;
        else if ((int)cnt.size() < k - 1) cnt[x] = 1;
        else {
            for (auto it = cnt.begin(); it != cnt.end(); )
                if (--it->second == 0) it = cnt.erase(it); else ++it;
        }
    }
    // verify each candidate with a second pass
    vector<int> res;
    for (auto& [v, _] : cnt) {
        int c = count(a.begin(), a.end(), v);
        if (c * k > (int)a.size()) res.push_back(v);
    }
    return res;
}

time, space. This is the Misra-Gries algorithm, and it is the standard streaming “heavy hitters” primitive.

The alternatives

MethodTimeSpaceNote
Boyer-Moore votingoptimal; needs verification
Hash map countingsimplest; also gives all counts
Sort, take the middlethe majority must occupy index
Randomised sampling expectedpick a random element, verify; succeeds with probability
Bit-by-bit majorityfor each bit, take the majority bit
Divide and conquerthe majority of the whole is a majority of some half

The sort-and-take-the-middle observation is worth remembering: if an element occupies more than half the array, it must cover position after sorting. One line, if a sort is affordable.

Range majority queries

“What is the majority element of ?” — harder, and there are several routes:

MethodCost
Randomised: sample positions in the range and verify each per query, high probability
Segment tree with Boyer-Moore merge per query + verification
Persistent segment tree over values, exact
Mo’s algorithm

The segment tree merge works because the Boyer-Moore pair (candidate, count) is mergeable: combining two ranges’ candidates cancels the smaller count. Verification still requires counting occurrences, typically with a sorted position list per value plus binary search.

Streaming relatives

ProblemAlgorithmSpace
MajorityBoyer-Moore
Elements Misra-Gries
Approximate frequenciesCount-Min sketch
Distinct countHyperLogLog
Uniform samplereservoir sampling

Why it is worth knowing

Boyer-Moore voting is the cleanest example of a cancellation argument: the answer survives because it outnumbers everything else combined. That framing — pair up and cancel — appears in parity arguments, in XOR tricks for “find the unique element”, and in several streaming algorithms.

See also: Boyer-Moore Voting · Reservoir Sampling · Segment Tree