题目
给你一个字符串 s ,请你去除字符串中重复的字母,使得每个字母只出现一次。需保证 返回结果的字典序最小(要求不能打乱其他字符的相对位置)。
注意:该题与 1081 https://leetcode-cn.com/problems/smallest-subsequence-of-distinct-characters 相同
示例 1:
输入:s = "bcabc"
输出:
"abc"
示例 2:
输入:s = "cbacdcbc"
输出:"acdb"
提示:
1 <= s.length <= 104
s
由小写英文字母组成
解法:一个个字符加入结果,已存在则丢弃,不存在则调整结果串末尾不符合小序的字符
class Solution {
public:
string removeDuplicateLetters(string s) {
int len = s.length();
if (len < 2)
return s;
unordered_map<char, int> map; //用hash表降低查找复杂度,空间换时间
for (int i = 0; i < len; ++i)
++map[s[i]];
string res;
for (int i = 0; i < len; ++i) {
if (res.find(s[i]) != string::npos) { //结果字符串已存在当前字符
--map[s[i]]; //丢弃该字符并减少其有效总个数
continue;
}
//结果字符串中最后一个字符可以删除,并且大于当前字符,则调整
while (!res.empty() && map[res.back()] > 1 && res.back() > s[i]) {
--map[res.back()];
res.pop_back();
}
res += s[i];
}
return res;
}
};
若需要调试,可用printf("res = %s\n", res.c_str());
其实有一个小问题,不容易让人转过来弯:为什么当前字符已存在就丢弃?不需要调整结果串里的那个重复字符和当前字符的相对顺序么?
可以自己举例模拟下,简单来说,既然元素在栈中(res)呆得住,就说明这个字符在那里符合前串的小序规定,不能轻易动,它只能被后续比它小的字符淘汰。