目录
一、题目描述
给你一个字符串 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 由小写英文字母组成
二、解题思路
这道题看题目要求字符去重并且字典序最小,字符要去重肯定要统计字符的出现次数,保持字符的相对顺序不变,是不是很熟悉的要求,没错,这题是单调栈和哈希的结合。需要注意的点有两个:
- 栈顶弹出的要求:当前字符比栈顶字符小时需要考虑是否弹出栈顶;
- 弹出的条件是当前字符没有在栈中出现(换句话说如果当前字符已经在栈中,则直接跳过不做处理);
三、代码实现
#include <bits/stdc++.h>
using namespace std;
//再用一个数组记录字符是否出现在栈中时间效率会比使用find好
//另外使用栈的时候注意可替代的数据结构,vector,string等都具有栈具备的操作,使用时灵活选择
//本题选用string替换栈效率就比直接使用栈或者vector的效率好
string removeDuplicateLetters(string s) {
int length = s.size();
unordered_map<char, int> chCnt;
for (int i = 0; i < length; i++) {
chCnt[s[i]]++;
}
string chSta;
for (int i = 0; i < length; i++) {
chCnt[s[i]]--;
if (chSta.empty()) {
chSta.push_back(s[i]);
}else {
//如果栈中已有这个字符就直接跳过
if (chSta.find(s[i]) != string::npos) continue;
while (!chSta.empty() && s[i] < chSta.back() && chCnt[chSta.back()] > 0) {
chSta.pop_back();
}
chSta.push_back(s[i]);
}
}
return chSta;
}
int main() {
string s = "aeace";
cout << removeDuplicateLetters(s);
return 0;
}