316. 去除重复字母
题目描述:
给你一个字符串 s
,请你去除字符串中重复的字母,使得每个字母只出现一次。需保证 返回结果的字典序最小(要求不能打乱其他字符的相对位置)。
示例 1:
输入:s = "bcabc"
输出:
"abc"
示例 2:
输入:s = "cbacdcbc"
输出:"acdb"
提示:
1 <= s.length <= 10^4
s
由小写英文字母组成
解题思路:单调栈解法
用一个单调栈维护字典序最小的字符串。由于对每个出现过的字母必须保证出现在最终的字符串中,直接遍历不确定当前出栈的字母后续是否还会出现,需要首先用字典存储每个字母出现的次数,在做出栈操作的时候,若当前字母的剩余出现次数非大于0,则即使不满足单调性该字母也必须进栈。
由于只包含小写字母,因此可以用26大小的vector来存储字母出现的次数,同理需要用一个vis数组保存当前字母是否已经在栈中,若已经在,就不需要重复进栈。
复杂度:由于遍历一遍字符串,且每个字母仅进出栈一次,时间复杂度O(n),空间复杂度:用了栈结构,O(n)
代码:
class Solution { public: string removeDuplicateLetters(string s) { int n = s.length(); if(n <= 1) return s; vector<int> flag(26, 0); vector<int> vis(26, 0); for(int i=0; i<n; i++) { flag[s[i]-'a']++; } stack<char> mystack; for(int i=0; i<n; i++) { while(!mystack.empty() && s[i] < mystack.top() && vis[s[i]-'a'] == 0) { if(flag[mystack.top()-'a'] > 0) { vis[mystack.top()-'a'] = 0; mystack.pop(); } else { break; } } if(vis[s[i]-'a'] == 0) { mystack.push(s[i]); vis[s[i]-'a'] = 1; } flag[s[i]-'a']--; } string res; while(!mystack.empty()) { res += mystack.top(); mystack.pop(); } reverse(res.begin(), res.end()); return res; } };