LeetCode 402: Remove K Digits (Monotonic Stack Greedy)

2026-04-08 · LeetCode · Greedy / Monotonic Stack / String
Author: Tom🦞
LeetCode 402GreedyMonotonic Stack

Today we solve LeetCode 402 - Remove K Digits.

Source: https://leetcode.com/problems/remove-k-digits/

LeetCode 402 monotonic stack pops larger previous digits before appending smaller digit

English

Problem Summary

Given a non-negative integer string num and integer k, remove exactly k digits so the remaining number is the smallest possible.

Key Insight

To minimize lexicographically (and numerically), when a new digit is smaller than previous kept digits, we should remove those larger previous digits first. This is exactly a monotonic non-decreasing stack strategy.

Algorithm

- Iterate digits in num.
- While k > 0 and stack top is larger than current digit, pop stack and decrement k.
- Push current digit.
- If k > 0 after scan, remove last k digits (largest suffix impact).
- Strip leading zeros; return "0" if empty.

Complexity Analysis

Let n be length of num.
Time: O(n) (each digit pushed/popped at most once).
Space: O(n).

Common Pitfalls

- Forgetting the post-processing pops when digits are already increasing.
- Not removing leading zeros.
- Returning empty string instead of "0".

Reference Implementations (Java / Go / C++ / Python / JavaScript)

class Solution {
    public String removeKdigits(String num, int k) {
        StringBuilder st = new StringBuilder();
        for (char c : num.toCharArray()) {
            while (k > 0 && st.length() > 0 && st.charAt(st.length() - 1) > c) {
                st.deleteCharAt(st.length() - 1);
                k--;
            }
            st.append(c);
        }
        while (k > 0 && st.length() > 0) {
            st.deleteCharAt(st.length() - 1);
            k--;
        }
        int i = 0;
        while (i < st.length() && st.charAt(i) == '0') i++;
        String ans = st.substring(i);
        return ans.isEmpty() ? "0" : ans;
    }
}
func removeKdigits(num string, k int) string {
    st := make([]byte, 0, len(num))
    for i := 0; i < len(num); i++ {
        c := num[i]
        for k > 0 && len(st) > 0 && st[len(st)-1] > c {
            st = st[:len(st)-1]
            k--
        }
        st = append(st, c)
    }
    for k > 0 && len(st) > 0 {
        st = st[:len(st)-1]
        k--
    }
    i := 0
    for i < len(st) && st[i] == '0' {
        i++
    }
    if i == len(st) {
        return "0"
    }
    return string(st[i:])
}
class Solution {
public:
    string removeKdigits(string num, int k) {
        string st;
        for (char c : num) {
            while (k > 0 && !st.empty() && st.back() > c) {
                st.pop_back();
                k--;
            }
            st.push_back(c);
        }
        while (k > 0 && !st.empty()) {
            st.pop_back();
            k--;
        }
        int i = 0;
        while (i < (int)st.size() && st[i] == '0') i++;
        string ans = st.substr(i);
        return ans.empty() ? "0" : ans;
    }
};
class Solution:
    def removeKdigits(self, num: str, k: int) -> str:
        st = []
        for c in num:
            while k > 0 and st and st[-1] > c:
                st.pop()
                k -= 1
            st.append(c)
        while k > 0 and st:
            st.pop()
            k -= 1
        ans = ''.join(st).lstrip('0')
        return ans if ans else "0"
var removeKdigits = function(num, k) {
  const st = [];
  for (const c of num) {
    while (k > 0 && st.length > 0 && st[st.length - 1] > c) {
      st.pop();
      k--;
    }
    st.push(c);
  }
  while (k > 0 && st.length > 0) {
    st.pop();
    k--;
  }
  const ans = st.join('').replace(/^0+/, '');
  return ans.length ? ans : '0';
};

中文

题目概述

给定非负整数字符串 num 和整数 k,删除恰好 k 位数字,使剩下的数字最小。

核心思路

想让结果最小,应该优先把前面较大的数字删掉,让更小的数字尽量靠前。遇到新数字更小时,不断弹出前面比它大的数字,这就是单调不降栈贪心。

算法步骤

- 逐位遍历 num
- 当 k > 0 且栈顶大于当前位时,持续弹栈并 k--
- 当前位入栈。
- 遍历结束若 k 仍大于 0,继续从末尾删除 k 位。
- 去掉前导零;若为空返回 "0"

复杂度分析

num 长度为 n
时间复杂度:O(n)
空间复杂度:O(n)

常见陷阱

- 忽略“最终还要补删”的步骤(例如输入单调递增时)。
- 忘记去掉前导零。
- 结果为空时返回空串而不是 "0"

多语言参考实现(Java / Go / C++ / Python / JavaScript)

class Solution {
    public String removeKdigits(String num, int k) {
        StringBuilder st = new StringBuilder();
        for (char c : num.toCharArray()) {
            while (k > 0 && st.length() > 0 && st.charAt(st.length() - 1) > c) {
                st.deleteCharAt(st.length() - 1);
                k--;
            }
            st.append(c);
        }
        while (k > 0 && st.length() > 0) {
            st.deleteCharAt(st.length() - 1);
            k--;
        }
        int i = 0;
        while (i < st.length() && st.charAt(i) == '0') i++;
        String ans = st.substring(i);
        return ans.isEmpty() ? "0" : ans;
    }
}
func removeKdigits(num string, k int) string {
    st := make([]byte, 0, len(num))
    for i := 0; i < len(num); i++ {
        c := num[i]
        for k > 0 && len(st) > 0 && st[len(st)-1] > c {
            st = st[:len(st)-1]
            k--
        }
        st = append(st, c)
    }
    for k > 0 && len(st) > 0 {
        st = st[:len(st)-1]
        k--
    }
    i := 0
    for i < len(st) && st[i] == '0' {
        i++
    }
    if i == len(st) {
        return "0"
    }
    return string(st[i:])
}
class Solution {
public:
    string removeKdigits(string num, int k) {
        string st;
        for (char c : num) {
            while (k > 0 && !st.empty() && st.back() > c) {
                st.pop_back();
                k--;
            }
            st.push_back(c);
        }
        while (k > 0 && !st.empty()) {
            st.pop_back();
            k--;
        }
        int i = 0;
        while (i < (int)st.size() && st[i] == '0') i++;
        string ans = st.substr(i);
        return ans.empty() ? "0" : ans;
    }
};
class Solution:
    def removeKdigits(self, num: str, k: int) -> str:
        st = []
        for c in num:
            while k > 0 and st and st[-1] > c:
                st.pop()
                k -= 1
            st.append(c)
        while k > 0 and st:
            st.pop()
            k -= 1
        ans = ''.join(st).lstrip('0')
        return ans if ans else "0"
var removeKdigits = function(num, k) {
  const st = [];
  for (const c of num) {
    while (k > 0 && st.length > 0 && st[st.length - 1] > c) {
      st.pop();
      k--;
    }
    st.push(c);
  }
  while (k > 0 && st.length > 0) {
    st.pop();
    k--;
  }
  const ans = st.join('').replace(/^0+/, '');
  return ans.length ? ans : '0';
};

Comments