Watch how a monotonic increasing stack greedily removes digits to form the smallest possible number.
Monotonic Stack LeetCode 402 ↗ Mediumnum representing a non-negative integer and an integer k,
remove k digits from the number so that the resulting number is the smallest possible."0").
fun removeKdigits(num: String, k: Int): String { val stack = mutableListOf<Char>() var k = k for (digit in num) { while (k > 0 && stack.isNotEmpty() && stack.last() > digit) { stack.removeLast() k-- } stack.add(digit) } // Remove remaining from end val result = stack.subList(0, stack.size - k) return result.joinToString("").trimStart('0').ifEmpty { "0" } }
The key insight is that to make the resulting number as small as possible, we want the most significant positions (leftmost digits) to be as small as possible. Whenever we encounter a digit that is smaller than the previous digit on the stack, we should remove that previous larger digit — it occupies a more significant position and makes the number larger.
We maintain a monotonic increasing stack. As we iterate through each digit of the
input number, we compare it with the top of the stack. If the stack top is greater than the current
digit and we still have removals left (k > 0), we pop the stack top (removing that digit)
and decrement k. We repeat this while the condition holds. Then we push the current digit.
k > 0, the stack is not empty, and the stack top is greater than the current digit: pop from the stack and decrement k.k > 0 removals remain, trim k digits from the end of the stack (these are the largest trailing digits)."0" if the result is empty).
Each digit is pushed and popped from the stack at most once, giving O(n) total operations.
The stack can hold at most n digits, so space is O(n). This is optimal since
we must examine every digit at least once.