掘金团队号上线,助你 Offer 临门! 点击查看详情
一、题目描述:
返回 字符串s中 字典序最小的子序列,该子序列包含 s 的所有不同字符,且只包含一次,
且1 <= s.length <= 1000 ,s 由小写英文字母组成
二、思路分析: 根据示例可发现规律,
- 如果一个字母只出现一次那么必定被选取到子序列中
- 按照字母升序排列的子串肯定是字典序最小的。
- 如果一个字母被选取且后续的字母有相同的,那么这个字母会被丢弃,因为如果后面存在比这个字母要小的字母,那么选择相同的字母字典序会更小,所以当前字母会被丢弃
- 考虑使用单调栈,先进来的字母可能会被移除,符合先进后出的原则
- 如果一个字母已经在栈中,那么如果后续有相同的字母,那么这个相同的字母会被丢弃,因为要保持不能存在重复的字母这条原则,且如果让这个相同的字母入栈,让已经在栈中的字母丢弃,则会导致当前子串的字典序不会更小,所以舍弃这个相同的字母会更好。
三、AC代码:
class Solution {
public String smallestSubsequence(String s) {
int len = s.length();
Character[] chars = s.toCharArray();
//需要一个栈
Deque stack = new ArrayDeque();
//需要一个boolean数组保存已经在栈中的元素,下标表示这个字母和字母a之间的差值,正好是26个一共,所以最大长度只能是26个小写字母
boolean[] existArr = new boolean[26]
//需要一个int数组保存在s中最后出现的位置的下标索引,用来丢弃元素
int[] lastIndexArr = new int[26];
for(int i = 0 ; i < len ;i++){
lastIndexArr[chars[i]-'a'] = i;
}
for(int i = 0; i < len;i++){
Character current = chars[i];
if(existArr[current-'a']){
continue;
}
while(!stack.isEmpty() && stack.getLast() > current && lastIndexArr[current-'a'] > i){
//移除当前栈顶元素
Character top = stack.removeLast();
//更改被移除元素对应的boolean数组的状态
existArr[top-'a']=false;
}
//将当前元素入栈
stack.addLast(current);
existArr[current-'a'] = true;
}
StringBuilder sb = new StringBuilder;
for(char c:stack){
sb.append(c);
}
return sb.toString();
}
四、总结:
更多的是查看规律问题,善于使用其他数据结构解决复杂问题,栈,队列等。