LeetCode 0316. 去除重复字母:单调栈
Posted Tisfy
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了LeetCode 0316. 去除重复字母:单调栈相关的知识,希望对你有一定的参考价值。
【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.”。至于为什么用栈,到后面就知道了。
string removeDuplicateLetters(string& s)
bool isInStack[26] = false; // isInStack[i]:字母'a'+i是否已经在栈中
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’重新入栈。
这就需要我们再开辟一个整数型的数组,来记录遍历到当前元素时,某个元素还会再出现多少次。
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 ) O(n) O(n),其中 n n n是字符串长度
- 空间复杂度 O ( C ) O(C) O(C),其中 C C C是字符集大小(26个小写英文字母,C=26)
推荐一篇描述更为详细的博客:由浅入深,单调栈思路去除重复字符
AC代码
C++
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
以上是关于LeetCode 0316. 去除重复字母:单调栈的主要内容,如果未能解决你的问题,请参考以下文章
LeetCode 907 子数组的最小值之和[单调栈] HERODING的LeetCode之路