一、题目

【LeetCode316】去除重复字母(单调栈+哈希)_字符串

二、思路

先读懂题意,删除重复的字母,得到最小的字符串。如babc,删除重复字母有两种结果bac,abc。abc小于bac,所以答案是abc。

遇到一个新字符 如果比栈顶小 并且在新字符后面还有和栈顶一样的 就把栈顶的字符抛弃了。

(1)前者的条件即单调栈的步骤(for中带while);可以用哈希表​​inst​​​统计当前字符是否在栈中。
(2)为了满足后者的条件,即如果栈顶元素大于当前遍历到的字符​​​s[i]​​​,并且栈顶元素在后面还存在,所以可以放心的pop掉。可以用哈希表​​cnt​​​统计s中剩余字符的出现次数。
(3)上面的循环操作后,得到最后的栈,把栈底到栈顶元素串成字符串。

【LeetCode316】去除重复字母(单调栈+哈希)_算法_02

三、代码

class Solution {
public:
string removeDuplicateLetters(string s) {
stack<char> st;
//剩余字符出现次数的哈希表
unordered_map<char, int> cnt;
//当前字符是否存在栈中
unordered_map<char, bool> inst;
for(auto& c: s){
++cnt[c];
}
for(int i= 0; i < s.size(); i++){
char c = s[i];
//当前字符已经在栈中则跳出循环
if(inst[c]){
--cnt[c];
continue;
}
//栈顶元素大于当前字符,并且栈顶元素在后面还存在,所以可以pop
while(!st.empty() && st.top() > c && cnt[st.top()] > 0){
inst[st.top()] = false;
st.pop();
}
st.push(c);
--cnt[c];
//当前c字符存在栈中
inst[c] = true;
}
string res;
//把栈底到栈顶元素串成字符串
while(!st.empty()){
res = st.top() + res;
st.pop();
}
return res;
}
};