思路:贪心+单调栈。
这道题和前几天做的那道“删除k位数字”那道题很像。
这里由于是按照字典序进行输出的,而且删除的地方我们也不知道,是随机的,这个时候其实就应该想到用单调栈进行解答,其实这样才能进行很好的存储操作。
再来,由于有重复的元素,我们需要计数操作。所以需要用哈希表进行对于字母的映射。
接下来就是对于入栈和压栈的判断:
首先就是对于入栈的操作:入栈时,我们需要判断这个条件:
对于重复元素的判断了,如果说将要压栈的这个元素在原栈里面已经有了,那么我们就不需要再压栈进去了,并且将这个元素的个数-1。
然后关键的就是对于出栈的操作:
1.我们知道,在进行出栈的时候,我们不能出栈字典序元素小的,也就是说,我们需要比较将要进来的这个元素和栈顶相比,哪一个字典序比较大;如果是栈顶的元素比较大,并且在后面的字符串里面,栈顶所对应的元素不止这一个,那么我们就让它出栈。
2.同时,在出栈的时候需要判断栈是不是空的。
3.再来,有人有问题在为什么在出栈的时候并不进行个数的减去呢?答案是在前面我们入栈的时候对于重复元素进行了-1,而且我们在入栈之后也对于这个元素进行了-1,这个元素如果一个都没有是不可能的,每一个元素都必须入栈,并且不能重复,这就决定了我们只要有一个字符入栈了,并且这个元素已经是唯一的了,就不会出栈了。如果出栈我们就-1的话,到真正需要入栈它的时候,它的计数已经成了0,我们就不能再入栈它了,所以这个问题我们在前面对于重复元素和入栈操作的时候已经处理过了。
上代码:
class Solution {
public:
string removeDuplicateLetters(string s) {
string buf;
map<char,int>m;
vector<int>vis(26,0);
for(int i=0;i<s.size();i++){
m[s[i]]++;
}
vector<char>res;
for(int i=0;i<s.size();i++){
if(vis[s[i]-'a']){
m[s[i]]--;
continue;
}
while(!res.empty()&&res.back()>s[i]&&m[res.back()]>0){
vis[res.back()-'a']=0;
res.pop_back();
}
m[s[i]]--;
vis[s[i]-'a']=1;
res.push_back(s[i]);
}
for(int i=0;i<res.size();i++)
buf+=res[i];
return buf;
}
};