【LetMeFly】316.去除重复字母:单调栈
力扣题目链接:https://leetcode.cn/problems/remove-duplicate-letters/
给你一个字符串 s
,请你去除字符串中重复的字母,使得每个字母只出现一次。需保证 返回结果的字典序最小(要求不能打乱其他字符的相对位置)。
示例 1:
输入:s = "bcabc"
输出:
"abc"
示例 2:
输入:s = "cbacdcbc"
输出:"acdb"
提示:
1 <= s.length <= 104
s
由小写英文字母组成
注意:该题与 1081 https://leetcode-cn.com/problems/smallest-subsequence-of-distinct-characters 相同
方法一:单调栈
这道题需要满足三个要求:
- 去重
- 按原始相对顺序
- 字典序最小
我们先来用栈实现一下“1.”和“2.”。至于为什么用栈,到后面就知道了。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| string removeDuplicateLetters(string& s) { bool isInStack[26] = {false};
stack<char> st; for (char& c : s) { if (isInStack[c - 'a']) { continue; } st.push(c); isInStack[c - 'a'] = true; }
string ans; while (st.size()) { ans += st.top(); st.pop(); } reverse(ans.begin(), ans.end()); return ans; }
|
上述代码中,我们用布尔类型的isInStack
来记录某个元素是否已经位于了栈中。遍历字符串时,如果某个元素还不在栈中,就将这个元素入栈,同时更新isInStack
如何实现字典序最小呢?很容易想到,越小的字母尽量地越靠前,就能使字典序尽可能地小。
因此,在遍历到一个不在栈中的字母时,如果前面有比它大的字母,并且前面这个字母以后还会出现,就让前面这个字母出栈。
例如,现在遍历到了字符串中的字符’a’,如果栈中上一个元素是’b’(’b’ > ‘a’),并且’b’以后还会再次出现,那么就让’b’出栈,等再次遇到’b’时,再让’b’重新入栈。
这就需要我们再开辟一个整数型的数组,来记录遍历到当前元素时,某个元素还会再出现多少次。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30
| string removeDuplicateLetters(string& s) { int remain[26] = {0}; for (char& c : s) { remain[c - 'a']++; } stack<char> st; bool isInStack[26] = {false}; for (char& c : s) { remain[c - 'a']--; if (isInStack[c - 'a']) continue; while (st.size() && st.top() > c && remain[st.top() - 'a']) { isInStack[st.top() - 'a'] = false; st.pop(); } st.push(c); isInStack[c - 'a'] = true; } string ans; while (st.size()) { ans += st.top(); st.pop(); } reverse(ans.begin(), ans.end()); return ans; }
|
- 时间复杂度$O(n)$,其中$n$是字符串长度
- 空间复杂度$O(C)$,其中$C$是字符集大小(26个小写英文字母,C=26)
推荐一篇描述更为详细的博客:由浅入深,单调栈思路去除重复字符
AC代码
C++
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31
| class Solution { public: string removeDuplicateLetters(string& s) { int remain[26] = {0}; for (char& c : s) { remain[c - 'a']++; } stack<char> st; bool isInStack[26] = {false}; for (char& c : s) { remain[c - 'a']--; if (isInStack[c - 'a']) continue; while (st.size() && st.top() > c && remain[st.top() - 'a']) { isInStack[st.top() - 'a'] = false; st.pop(); } st.push(c); isInStack[c - 'a'] = true; } string ans; while (st.size()) { ans += st.top(); st.pop(); } reverse(ans.begin(), ans.end()); return ans; } };
|
同步发文于CSDN,原创不易,转载请附上原文链接哦~
Tisfy:https://letmefly.blog.csdn.net/article/details/127011739