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'.
- 1 <= k <= num.length <= 10⁵
- num consists of only digits
- num does not have any leading zeros except for '0' itself
num = "1432219", k = 3"1219"num = "10200", k = 1"200"num = "10", k = 2"0"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".
# 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.
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]"12".Monotonic Stack Reduction Strategy
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.
Edge Cases
1. Remove trailing digits if kInitial > 0. 2. Handle leading zeros. 3. Return "0" if empty.