InterviewPrepKit

Home / Coding / Heap & Priority Queue

Smallest Number in Infinite Set

medium Original ↗
Solving tips
  • Recognize this as a 'mostly-regular sequence with a few exceptions' design: don't materialize the infinite set, track it with one integer pointer plus the popped-then-added-back values.
  • Keep a min-heap for the added-back numbers guarded by a companion set so duplicates never enter the heap; popSmallest returns the heap top if non-empty, else the pointer value.
  • Aim for O(log n) popSmallest and addBack with O(n) space, where n is the number of exceptions below the pointer.
  • Pitfall: addBack must ignore num >= current (it was never popped) and must sync the set when you pop from the heap, or a later valid addBack gets wrongly rejected.

Problem

Design a data structure that conceptually contains all positive integers 1, 2, 3, ... (an infinite set). Implement a class SmallestInfiniteSet supporting:

  • SmallestInfiniteSet() — initialize the set so it contains every positive integer.
  • popSmallest() -> int — remove and return the smallest integer currently in the set.
  • addBack(num) -> None — add the positive integer num back into the set, but only if it is not already present (adding a number that is still in the set does nothing).

The challenge is that the set is infinite, so you cannot materialize all its elements. You must track only what has changed relative to the pristine 1, 2, 3, ... sequence.

Examples

  • Sequence of calls: addBack(2) → set already contains 2, no-op. popSmallest() → returns 1 (set now conceptually {2, 3, 4, ...}). popSmallest() → returns 2. popSmallest() → returns 3. addBack(1)1 was popped, so it re-enters; set is {1, 4, 5, ...}. popSmallest() → returns 1 (the re-added value is now the smallest). popSmallest() → returns 4. popSmallest() → returns 5.

  • Fresh instance: popSmallest() returns 1, then 2, then 3 — the naturals in order until something is added back.

Constraints

  • 1 <= num <= 1000.
  • At most 1000 total calls to popSmallest and addBack combined.
  • popSmallest is always called when the set is non-empty (it never runs dry, since the set is infinite).

Think about it first

Hint 1 You never need to store the infinite tail explicitly. Everything from some threshold onward is untouched and can be represented by a single integer: "the next never-yet-popped number."
Hint 2 Only numbers *below* that threshold can be irregular — those are the ones popped and possibly added back. Keep those in a structure that hands you the minimum quickly.
Hint 3 Use an integer pointer `current` (starts at 1) for the untouched tail, plus a **min-heap** and a companion set for numbers added back below `current`. `popSmallest` prefers the heap if it holds something smaller than `current`; otherwise it returns `current` and advances it. The set prevents inserting duplicates into the heap.
Your workspace Not runnable by design — this is your interview scratchpad. Saved on this device.