给你一个字符串 s ,请你去除字符串中重复的字母,使得每个字母只出现一次。需保证 返回结果的字典序最小(要求不能打乱其他字符的相对位置)。
示例 1:
输入: s = "bcabc"
输出: "abc"
示例 2:
输入: s = "cbacdcbc"
输出: "acdb"
思路
题目想要的是一个字典序最小,即尽量由小到大排列的字符串;
那么对于一个元素:
1)如果前面已经出现过该元素,因为该元素符合多个的条件2),所以他的后继元素必然大于该元素,即选用该位置相比前面的位置字典序必然更大,所以直接去掉
2)排查前一个字符,如果前一个字符>该字符且后面还会出现,那就可以去掉前一个元素让字典序更小。如果前一个字符只会出现一次,那就不能去掉,直接加入该元素到结果集
因为比较的是和pop的最后一个加入结果集的元素,符合后进先出,所以用stack结构
public String removeDuplicateLetters(String s) {
//值小的要排在前面
char[] arr = new char[26];
boolean[] used = new boolean[26];
for (int i = 0; i < s.length(); i++) {
arr[s.charAt(i) - 'a']++;
}
Deque stack = new ArrayDeque<Character>();
for (int i = 0; i < s.length(); i++) {
arr[s.charAt(i) - 'a']--;
//如果已经放入过直接跳,因为该位置肯定比之前出现的位置靠后,字典序最好也只是和上一个位置相等
if (used[s.charAt(i) - 'a']){
continue;
}
//如果前面的字符比该字符大且后面还会出现那就pop掉
while (!stack.isEmpty() && arr[(char)stack.peek() - 'a'] > 0 && (char)stack.peek() > s.charAt(i)){
used[(char)stack.peek() - 'a'] = false;
stack.pop();
}
stack.push(s.charAt(i));
used[s.charAt(i) - 'a'] = true;
}
StringBuffer res = new StringBuffer();
while(!stack.isEmpty()){
res.insert(0, stack.pop());
}
return res.toString();
}