解题的前情提要
要理解贪心的思想,每一步都要选取当前最优的
适用范围: 线性的情况下,一般使用贪心和动态规划较多
常使用的数据结构: 贪心策略常结合栈数据结构
实现思想
数值的比较 1)总位数2)对应数字位上的数值
- 在位数不同的情况下,位数越多的数值越大
- 在位数相同的情况下,从最高位开始比较,最高位数值越大的数值越大,若相同比较次高位…直到比较出结果
思考过程
现在要考虑明白本怎么获取到正确的结果
从样例开始分析入手:
第一位为1,第二位为4
- 删除1得到新的数为432219
- 删除4得到新的数为132219
很明显后者比前者小,这个规律是在于,后一位的数值比当前数值大,肯定不能让后一位挪到前一位,必然导致数值增大,概括来说就是取二者之间最小的那位
在这个过程删除的操作一定是从前往后进行的,结果在最后才得到,符合栈数据结构的特点,可以考虑配合栈来实现。
特殊情况
之前所讨论的是一般情况,除此之外还要考虑别的特殊情况
情况一:
Q:当后面的元素一直小于当前最后的元素,是否一直舍弃最后的元素?
A:这是实现思想中的核心,在仍可以删除的情况下为取得最优解,一定要选择较小的数值在新的位置上
(这里面我原先有点没想明白,所以采取了从头遍历的方案,导致超时,实际上用while循环来实现即可)
情况二:
Q: 如果序列是单调递增的怎么办,也就没满足普遍情况的删除情况?
A:可以从后往前删除k个元素基克尔
情况三:
Q:怎么删除结果序列中多余的前置0
A:直接从源头上遏制,当栈中元素为空,且要压入是0的情况,不将该0压入里面
而且在实现的过程中,要考虑栈是否为空,k是否为0,结果字符串是否为空
数据结构
经过前面的分析之后,我们可以使用栈这一数据结构,在具体实现的时候可以使用vector,注意时要利用栈的特点,但并不一定要使用栈,使用了vector的好处在于便于将结果存入字符串中,而且栈也支持压入(push_back)和弹出(push_back)
实现代码
代码一
代码二
class Solution {
public:
string removeKdigits(string num, int k) {
vector<char> s;
string re="";
for(int i=0;i<num.size();i++){
while(s.size()!=0&&k&&num[i]<s[s.size()-1]){
s.pop_back();
k--;
}
if(s.size()==0&&num[i]=='0'){
continue;
}
else{
s.push_back(num[i]);
}
}
while(s.size()!=0&&k){
s.pop_back();
k--;
}
for(int i=0;i<s.size();i++){
re.append(1,s[i]);
}
if(re==""){
return "0";
}
return re;
}
};
代码二主要优化了代码一的数字和字符的转换,这个转换我觉得是不必要的,本身用字符编码的特点也能比较出实际的数值大小
提交结果及分析
虽然有两层循环,但时间复杂度是O(n)的,只是一个线性的过程