Learning pathOriginal reference
Lesson 12 of 12

Optional: keep only the best k

Use a small min-heap to retain the largest arrivals, and justify the invariant and costs.

Make the weakest retained item easy to discard

To keep the largest k values while reading n arrivals, retain candidates in a min-heap. The goal is largest values, but the next value you may discard is the smallest retained candidate. Push the arrival; if size exceeds k, pop the minimum.

For k = 3 and arrivals 5 1 9 9 2 7, the retained multisets become {5}, {1,5}, {1,5,9}, {5,9,9}, {5,9,9}, and {7,9,9}. This sorted notation explains the set of values; it is not the heap’s physical layout. Duplicate occurrences count separately.

The invariant proves what survives

After every prefix, the heap contains its largest min(k, prefix length) occurrences. Adding one new candidate can create k + 1 candidates; their smallest cannot be needed among their largest k. Previously discarded values do not become more competitive when another value arrives.

With 1 ≤ k ≤ n, the final heap contains exactly k values. Its top is the kth largest occurrence overall. To print all retained values in descending order, pop them into a vector in ascending order and reverse that vector.

Bound the live size, not the entire input

The heap briefly reaches k + 1 values. Each arrival performs heap updates on that bounded size, giving O(n log(k + 1)) amortized time and O(k) logical storage. At k = 1, the algorithm is linear. Keeping a result vector for all k outputs still uses O(k) total logical storage.

If all input is already stored and streaming storage is irrelevant, sorting once can be simpler. The bounded heap is useful when keeping only k candidates saves memory or fits the arrival model.

Finish with the right checks

Test k = 1, k = n, repeated maximum values, all-negative values, and ties around the kth position. For general container simulations, also test an empty request, one insertion then removal, draining to empty, and inserting again afterward.

Choose the operation first: vector for indexing, deque for two ends, queue for oldest-first, stack for newest-first, and a priority queue for changing extrema. Always count copies, removals, comparison costs, and peak simultaneous storage in addition to the visible loop.

Container workbench

Insert values, then remove the next accessible item. Priority queue values are shown sorted for explanation, not as an internal heap.

80
31
52

Next removal: 5. Size: 3.

Guided simulation · Change the inputs to test your understanding.

Pause & predict

Why use a min-heap when retaining the largest k values?

Choose an answer
Try it yourself

Turn the idea into code

Read n, k, then n integers with 1 ≤ k ≤ n ≤ 200000. Print the kth largest occurrence, counting duplicates, while using O(k) logical container storage. For 5 1 9 9 2 7 with k = 3, print 7.

Give me a hint

Maintain the largest k arrivals in a min-heap. At the end, its smallest retained value has exactly the required rank.

Show the explained solution

After each arrival, the invariant keeps the largest k occurrences seen so far. The final minimum of those retained values is the kth largest overall. The program does not store the whole input and costs O(n log(k + 1)) amortized time.

C++23
// Complete C++23 program. Input: n k, then n integers; 1 <= k <= n.
#include <functional>
#include <iostream>
#include <queue>
#include <vector>
int main() {
    int n = 0, k = 0;
    std::cin >> n >> k;
    std::priority_queue<int, std::vector<int>, std::greater<int>> best;
    for (int i = 0; i < n; ++i) {
        int x = 0;
        std::cin >> x;
        best.push(x);
        if (static_cast<int>(best.size()) > k) best.pop();
    }
    std::cout << best.top() << '\n';
}

Your notes

Ready for the next idea?

Mark complete when you can explain it yourself.

From a problem to a programIdentify the input, output, and constraints, then translate a small plan into C++.Variables, types, and remembered valuesChoose a representation, initialize it, and understand what assignment really changes.Arithmetic without surprisesPredict division and remainder, widen before multiplication, and format decimal answers.Conditions and logical decisionsBuild exclusive categories, combine comparisons, and protect operations with short-circuit logic.Optional: other ways to chooseRecognize switch for exact choices and the conditional operator for choosing a value.For loops: make repetition preciseTrace initialization, condition, body, and update—and avoid an extra iteration.While, do-while, and stopping rulesChoose a loop from its stopping condition and read the exact input format.Break, continue, and early answersDistinguish leaving a loop from skipping one iteration, without losing required input.Five patterns worth understandingUse sums, counts, best-so-far candidates, products, and flags to process a stream.Nested loops: rows and columnsTranslate a shape into two loop roles and count the total work.Take a number apart, one digit at a timeUse remainder and division to process decimal digits, including zero.Multiple cases and a debugging mindsetCombine the patterns, isolate each case, and test the boundaries that can break your idea.Arrays: give every value a placeUnderstand indices, initialization, capacity, active length, and the first safe array loop.Scan, count, search, and compareDistinguish values from positions and preserve the exact tie rule a problem asks for.Change a sequence without losing itUpdate, copy, compare, reverse, and inspect neighbours using the correct bounds.Matrices: think in two coordinatesTraverse tables, total rows and columns, inspect diagonals, and protect grid neighbours.Characters become stringsSeparate characters from numbers, then safely inspect and edit managed text.Read the text the problem actually givesChoose words or full lines, preserve empty cases, and reset only the state that needs it.Scan text: count, filter, transformBuild a result from matching characters without losing leading zeros or skipping shifted text.Join, compare, and find textLearn content comparison, lexicographical order, substring counts, and the not-found sentinel.