题目
题解
这道题,还真木有想出来
看了一下官方视频解答,讲的比较好
大致思路:
例如:
输入:s = "bcabc"
输出:"abc"
b->bc>bca(由于c比a字典序大,所以这次考虑可以把c弹出去,看到c在后面还会出现,所以可以弹出去)->ba->a(同理弹b)->ab->abc
可以看到,弹出的时候满足后进先出,所以可以基本确定这里需要使用“栈”结构。
确定使用栈后,可以这么来看,一开始b压入,c压入。当要压入a时,因为此时栈顶元素“c”比“a”字典序大。如若a能在c前面肯定总字典序要更小
那么这时候看“a”后面还有没有“c”,显然有,那么可以把“c”pop出去,再把“a”压入。
Tip:显然如果后续在字符串遇见已经在栈内的字符。我们可以直接跳过。 (因为如果他在栈顶。没必要。如果在栈内,栈内的“它”肯定前小后大,所以忽略)
(https://leetcode-cn.com/problems/remove-duplicate-letters/solution/zhan-by-liweiwei1419/) 这个题解后四段更为详细
代码
public class Solution {
public String removeDuplicateLetters(String s) {
int [] visited = new int[26]; //已经存在于栈中 标志数组
int [] lastIndex = new int[26]; //存在字符,最后一次在字符串出现的index
for (int i = 0; i < s.length(); i++) {
lastIndex[s.charAt(i)-'a'] = i; //记录所有存在字符,最后一次出现的index
}
Deque<Character> ans = new ArrayDeque<Character>(); //栈
for (int i = 0; i < s.length(); i++) {
if (visited[s.charAt(i)-'a'] == 1){ //如果栈中已经存在,忽略
continue;
}
while (!ans.isEmpty()&&ans.peekLast()>s.charAt(i)&&i<lastIndex[ans.peekLast()-'a']){ //如果栈顶元素比待加入的字符 字典序大 ,则看一下该栈顶元素在后面是否还会出现
char top = ans.removeLast(); //移除栈顶元素
visited[top-'a'] = 0; //栈顶元素,置为栈中未出现
}
ans.addLast(s.charAt(i)); //将字符串的待加入字符加入栈顶
visited[s.charAt(i)-'a'] = 1; //标志为栈中已存在
}
StringBuilder stringBuilder = new StringBuilder();
for (char c:ans){
stringBuilder.append(c);
}
return stringBuilder.toString();
}
}
StringBuffer和StringBuilder区别:https://segmentfault.com/a/1190000017909550
stack:栈 数据是后进先出(LIFO)
queue:队列 数据是先进先出(FIFO)
deque:双端队列 数据可以从两端进出