Algorithm

Remove K Digits

Monotonic Stack Pattern

Remove K Digits

Given string num representing a non-negative integer, and an integer k, return the smallest possible integer after removing k digits from num. Note: The result should not have leading zeros. If the result is an empty string, return '0'.

CONSTRAINTS
  • 1 <= k <= num.length <= 10⁵
  • num consists of only digits
  • num does not have any leading zeros except for '0' itself
EXAMPLE 1
Input: num = "1432219", k = 3
Output: "1219"
The digits 4, 3, and one 2 are removed as they are identified as local peaks relative to their successors.
EXAMPLE 2
Input: num = "10200", k = 1
Output: "200"
Removing the 1 creates the sequence '0200', which simplifies to '200' after stripping leading zeros.
EXAMPLE 3
Input: num = "10", k = 2
Output: "0"
All digits are removed, resulting in an empty state which defaults to '0'.
What if the string is already in increasing order?
If the string is like '12345', no peaks will be found. The while-loop at the end will simply chop off the last k digits, leaving the smallest possible prefix.

A digit's value depends far more on where it sits than on what it is: the leftmost digit is worth thousands, the rightmost almost nothing. So to shrink the number, the digits you most want to delete are large ones sitting in high, leftward positions. Trying every choice of which k digits to drop is exponential, so we need a rule that picks correctly in one pass.

Here's the rule. Read the digits left to right and build the answer on a stack. The best answer has its digits rising as much as possible near the front, so whenever the digit you're about to add is smaller than the digit currently on top, that top digit is a bump that makes the number bigger than it needs to be — spend one deletion to pop it (as long as you still have deletions left), and keep popping while the new digit undercuts the top. In "43…", meeting the 3 tells you the 4 is wasteful: dropping it to reach "3…" beats any other single removal, because it lowers the most significant place.

Notice what the stack ends up holding: digits kept in (mostly) increasing order, with the pops happening exactly when a smaller digit threatens to break that order. That's a monotonic stack — an ordinary stack maintained in sorted order — paired here with a deletion budget k that limits how many out-of-order pops you're allowed.

Three loose ends: if you finish the string with budget left over (the digits were already ascending, like "1234"), just chop the last k digits, since the smallest number keeps the smallest front. Then strip leading zeros, and if nothing remains, the answer is "0".

python
# Monotonic stack + deletion budget (O(N) Time, O(N) Space)
stack = []
for digit in num:
    while k > 0 and stack and stack[-1] > digit:
        stack.pop()          # drop a larger digit sitting in a more significant spot
        k -= 1
    stack.append(digit)

final = stack[:-k] if k > 0 else stack   # budget left over: trim from the end
res = "".join(final).lstrip('0')
return res if res else "0"

Each digit is pushed once and popped at most once, so it's linear. And because a digit is only ever removed when a strictly smaller one can take its place further left, every deletion provably lowers the result.

Worked Example:num = "1432", k = 2
- 1 → push. Stack: [1]
- 4 → 4 > 1, no bump, push. Stack: [1, 4]
- 3 → 3 < 4, pop 4 (k→1), push 3. Stack: [1, 3]
- 2 → 2 < 3, pop 3 (k→0), push 2. Stack: [1, 2]
- Result: "12".
Interactive Strategy Visualization
GREEDY MINIMIZATION ENGINE

Monotonic Stack Reduction Strategy

1
4
3
2
2
1
9
Small Number Builder
Removals
3

Mental Model

  • Greedy Choice: Smaller digits at the start (most significant positions) make the number smaller.
  • Descending Peak: If we find a smaller digit than the previous one, the previous one must be removed.
LOGICSTEP 1/12
Process '1432219' with k=3.
TIP

Edge Cases

1. Remove trailing digits if kInitial > 0. 2. Handle leading zeros. 3. Return "0" if empty.

O(2ᴺ) Try Every Removal
O(N) Monotonic Stack + Budget