labuladong算法公众号学习笔记
LeetCode316 去除重复字母
题目思考
有三点要求:
- 要去重
- 不能打乱s中字符出现的相对顺序
- 字典序最小(比如“abc”的字典序就比“bac”的字典序小)
思路
先用栈实现前两个要求
String removeDuplicateLetters(String s){
//存放去重结果
Stack<Character> stk = new Stack<>();
//布尔数组初始值为false,记录栈中是否存在某个字符
//输入字符均为ASCII字符
boolean[] inStack = new boolean[256];
for(char c : s.toCharArray()){
//如果字符c存在栈中,直接跳过
if(inStack[c]) continue;
//如果不存在,则插入栈顶并标记为存在
stk.push(c);
inStack[c] = true;
}
StringBuilder sb = new StringBuilder();
while(!stk.empty()){
sb.append(stk.pop);
}
//插入的元素顺序相反需要reverse一下
return sb.reverse().toString();
}
要求三:
如果当前字符‘a’比之前的字符字典序小,就有可能需要把前面的字符pop出栈,让‘a’拍在前面。而且分一下情况:
- 如果 stk.peek( ) > c 这个字符以后还会出现,就可以pop出去。
- 如果 stk.peek( ) > c 这个字符之后不再出现,就不能简单pop出去。
- 关键在于让算法知道字符’a’之后有几个’b’和’c’
String removeDuplicateLetters(String s){
//存放去重结果
Stack<Character> stk = new Stack<>();
//维护一个计数器记录字符串中字符的数量
//因为输入为ASCII字符,大小256够用
int[] count = new int[256];
for(int i = 0;i < s.length; i++){
count[s.charAt(i)++];
}
//布尔数组初始值为false,记录栈中是否存在某个字符
//输入字符均为ASCII字符
boolean[] inStack = new boolean[256];
for(char c : s.toCharArray()){
//每遍历过一个字符,都将对应的计数减一
count[c]--;
//如果字符c存在栈中,直接跳过
if(inStack[c]) continue;
while(!stk.isEmpty() && stk.peek() > c){
//若之后不存在栈顶元素了,则停止pop
if(count[stk.peek()] == 0) break;
//若之后还有,则可以pop
inStack[stk.pop] = false;
}
//如果不存在,则插入栈顶并标记为存在
stk.push(c);
inStack[c] = true;
}
StringBuilder sb = new StringBuilder();
while(!stk.empty()){
sb.append(stk.pop);
}
//插入的元素顺序相反需要reverse一下
return sb.reverse().toString();
}
利用count计数,来查找时候后面还有和栈顶相同的元素。