题目描述
给你一个以字符串表示的非负整数 num
和一个整数 k
,移除这个数中的 k
位数字,使得剩下的数字最小。请你以字符串形式返回这个最小的数字。
示例 1 :
输入:num = "1432219", k = 3 输出:"1219" 解释:移除掉三个数字 4, 3, 和 2 形成一个新的最小的数字 1219 。
示例 2 :
输入:num = "10200", k = 1 输出:"200" 解释:移掉首位的 1 剩下的数字为 200. 注意输出不能有任何前导零。
示例 3 :
输入:num = "10", k = 2 输出:"0" 解释:从原数字移除所有的数字,剩余为空就是 0 。
提示:
1 <= k <= num.length <= 105
num
仅由若干位数字(0 - 9)组成- 除了 0 本身之外,
num
不含任何前导零
代码实现
class Solution {
public:
string removeKdigits(string num, int k) {
stack<char> stk;
// 使用栈维护一个单调递增的序列,但是移除的元素不能多于k个
for (char digit : num) {
while (k > 0 && !stk.empty() && stk.top() > digit) {
stk.pop();
--k;
}
stk.push(digit);
}
// 如果 k 仍然大于 0,从栈顶移除额外的元素
while (k > 0 && !stk.empty()) {
stk.pop();
--k;
}
// 构建结果字符串,此时栈中的序列为从底到顶的顺序
string result;
while (!stk.empty()) {
result.push_back(stk.top());
stk.pop();
}
reverse(result.begin(), result.end());
// 移除结果字符串中的前导零
int start = 0;
while (start < result.length() && result[start] == '0') {
++start;
}
result = result.substr(start);
return result.empty() ? "0" : result;
}
};
算法步骤
-
栈的使用: 栈用于维护一个单调递增的数字序列。我们逐个遍历字符串
num
中的每个数字,并依次处理它们。 -
处理当前数字:
- 对于每个数字
digit
,如果当前栈顶的数字大于digit
且还可以移除更多数字(即k > 0
),则弹出栈顶元素(这意味着移除一个较大的数字)。 - 减少
k
的值(每弹出一个数字,k
减一)。 - 将当前数字
digit
压入栈中。
- 对于每个数字
-
检查是否还需要移除数字:
- 如果遍历完所有数字后,
k
仍大于 0,这意味着我们还需要继续从栈中移除元素,直到k
变为 0 或栈为空。
- 如果遍历完所有数字后,
-
构建结果字符串:
- 从栈底到栈顶将数字依次取出并放入结果字符串
result
中。此时,result
中的数字顺序是从高位到低位的。 - 因为栈是后进先出的,所以需要对
result
字符串进行反转,以得到正确的顺序。
- 从栈底到栈顶将数字依次取出并放入结果字符串
-
移除前导零:
- 遍历
result
字符串,从左到右检查并跳过前导零。 - 使用
substr
方法截取掉前导零后的字符串作为最终结果。
- 遍历
-
返回最终结果:
- 如果结果字符串为空(即所有数字都被移除了),返回
"0"
。 - 否则,返回处理后的字符串。
- 如果结果字符串为空(即所有数字都被移除了),返回
复杂度分析
- 时间复杂度:O(N),其中 N 是字符串
num
的长度。每个元素最多被推入和弹出栈一次。 - 空间复杂度:O(N),在最坏的情况下(例如输入的数字单调递增),栈可能需要存储所有的数字。
这个方法利用了栈的特性来维护数字的顺序,确保在遵守移除数字的限制的同时获得最小可能的数字。