316. 去除重复字母
给你一个字符串 s ,请你去除字符串中重复的字母,使得每个字母只出现一次。需保证 返回结果的字典序最小(要求不能打乱其他字符的相对位置)。
示例 1:
输入:s = "bcabc"
输出:"abc"
示例 2:
输入:s = "cbacdcbc"
输出:"acdb"
提示:
- 1 <= s.length <= 104
- s 由小写英文字母组成
解题思路:
知道要利用「单调栈」的思想,但是没做出来~,最后参考官方思路写的。
维护一个栈,存放结果字母。从左往右遍历字符串,当有新字母加入时:
- 判断栈顶字母是否大于新字母,若大于,应该踢出栈顶元素加入新元素
- 重复步骤 1
- 步骤 1 边界条件:栈里有元素 && 栈顶元素大于新元素 && 后面还有栈顶元素
方法一:单调栈
public String removeDuplicateLetters(String s) {
// 小写字母26个,表示字母是否已经加入栈
boolean[] visited = new boolean[26];
// 每个字母出现次数
char[] counts = new char[26];
for (int i = 0; i < s.length(); i++) {
counts[s.charAt(i) - 'a']++;
}
StringBuilder sb = new StringBuilder();
for (int i = 0; i < s.length(); i++) {
char ch = s.charAt(i);
if (!visited[ch - 'a']) {
// 栈里有元素 && 栈顶元素大于新元素 && 后面还有栈顶元素
while (sb.length() > 0 && sb.charAt(sb.length() - 1) > ch && counts[sb.charAt(sb.length() - 1) - 'a'] > 0) {
visited[sb.charAt(sb.length() - 1) - 'a'] = false;
sb.deleteCharAt(sb.length() - 1);
}
visited[ch - 'a'] = true;
sb.append(ch);
}
counts[ch - 'a']--;
}
return sb.toString();
}