1. 题目来源
2. 题目说明
3. 题目解析
很经典的一道贪心问题。
思路:
- 若已经从前到后考虑完了前
i-1
位,目前考虑第i
位,则这两个大小关系有三种情况:s[i-1]>s[i]
,删掉s[i-1]
,这样删除,就能保留s[i]
,使其更小。在此需要再去看s[i-2]
是否也大于s[i]
直至不大于,或者删除机会用完。这个思想,就是单调栈啊s[i-1]<s[i]
,不删s[i-1]
,同理,保留s[i-1]
,更小s[i-1]=s[i]
,不删s[i-1]
,这个不用删除,把删除机会留给后面
- 如果删除机会没用完的话,那么就直接从后缀开始删。单调栈,得到的序列是递增的,所以删掉后缀是最好的决策
单调栈的思想解决本题很适合。
从 dp
方向考虑每一个状态,确保每个状态都不遗漏,再发现规律转换到贪心,对应到本题的思考过程是很重要的。
官方题解讲解的不错,貌似也是 2020年8月16日,大疆笔试原题。
代码:
class Solution {
public:
string removeKdigits(string num, int k) {
k = min(k, (int)num.size());
string res;
for (auto e : num) {
// 如果有删除机会,且res还有字符,res的最后一个字符大于e,即破坏单调性,则出栈
while (k && res.size() && res.back() > e) {
k --;
res.pop_back();
}
res += e; // 入栈
}
while (k --) res.pop_back(); // 没有删干净,则删除其后缀
k = 0;
while (k < res.size() && res[k] == '0') k ++; // 找前导0个数
if (k == res.size()) res += '0'; // 整体都是0,则末尾补上一个0,方便substr
return res.substr(k); // 返回从k位置到末尾的子串
}
};