地址 https://leetcode-cn.com/problems/remove-duplicate-letters/
给你一个字符串 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 由小写英文字母组成
算法1
单调栈和哈希
我们首先需要记录字母在字符串中的出现次数,首选哈希
然后只出现一次的的字母肯定是不能去除的,但是出现多次的字母 如何做取舍? 使用什么数据结构?
使用栈的话,当前字母和栈顶字母进行比较,如果栈顶字母在字符串中出现多次且字母序比当前的字母的大,那么就出栈。
由于每个字母只需要选择一次,已经在栈中的字母不必进行上述比较。
如图
记录字母出现的次数 和字母是否已经存在栈中适应哈希
使用单调栈 排序可能的 字母序比较小的选择
C++ 代码
class Solution { public: int mm[26]; stack<char> st; int isInSt[26]; string removeDuplicateLetters(string s) { for (int i = 0; i < s.size(); i++) { mm[s[i]-'a']++; } for (int i = 0; i < s.size(); i++) { if(isInSt[s[i]-'a'] ==0){ while (!st.empty()&& isInSt[s[i]-'a'] == 0) { char top = st.top(); if (mm[top-'a'] > 1 && s[i]< top ) { st.pop(); mm[top-'a']--; isInSt[top-'a']--; } else { break; } } //无论如何 此刻总要push进去的 st.push(s[i]); isInSt[s[i]-'a']++; } else { mm[s[i]-'a']--; } } string ans = ""; while (!st.empty()) { ans.insert(ans.begin(), st.top()); st.pop(); } return ans; } };