价值:记录学习过程的思考,本身就是一场动态规划的前生,记忆化搜索。
单调栈:及时去掉无用数据,保证栈中数据有序。
Problem: 1081. 不同字符的最小子序列
思路
讲述看到这一题的思路 暴力做法:统计(为了去重字符,得到有效字符)->全排列(有效字符生成字串)->顺序依赖([i,j原串、单个字串]依赖原来顺序,判别字串有效,有效条件单个字串判断完了j==字串n-1索引),取结果
单调栈:枚举到的当前元素与栈顶元素决策,考虑入栈还是枚举出栈。
学习到的思路:
有顺序依赖,除了双指针对比遍历,可以考虑栈顶入栈时比较进行维护,轻量级维护有序,扩大范围。。。
Code
class Solution {
public String smallestSubsequence(String s) {
int n = s.length();
char[] chars = s.toCharArray();
//顺序覆盖,记录元素最后出现的索引位置
int[] lastIndex = new int[26];
for(int i = 0; i<chars.length;i++){
lastIndex[chars[i]-'a'] = i;
}
Deque<Character> stack = new ArrayDeque<>();
//记录下访问过没有 {true,false...26}
boolean[] visited = new boolean[26];
for(int i =0 ; i < n ; i++){
//如果之前访问过了,后边再次看到,直接跳过了,because,前边已经放到了正确的位置上===单调位置
if(visited[chars[i] - 'a']){
continue;
}
//栈里边有元素 && 栈顶元素大于遍历到的元素 && 栈顶元素后续还能看到 ===》 弹栈,当前小元素入栈
while(!stack.isEmpty() && stack.peekLast() > chars[i] && lastIndex[stack.peekLast() - 'a']>i){
Character top = stack.pollLast();
visited[top - 'a'] = false;
}
//一般朴素情况,便利到的元素添加到栈内
stack.addLast(chars[i]);
visited[chars[i] - 'a'] = true;
}
StringBuilder sb = new StringBuilder();
for(char c : stack){
sb.append(c);
}
return sb.toString();
}
}
//暴力
public String smallestSubsequence(String s) {
int n = s.length();
char[] chars = s.toCharArray();
// quchong
int[] scount = new int[26];
for(int i = 0; i<chars.length;i++){
scount[chars[i]-'a']++;
}
//
List<Character> arr = new ArrayList();
for(int i =0; i< 26 ; i++){
if(char[i]>0){
arr.add(char[i] + 'a');
}
}
//gen quan pai lie
List<String> ans = new ArrayList<>();
ans = dfs(arr.toArray(),0,new StringBuilder(),ans);
//s[0~i] &&
for(String an : ans){
int j = 0;
int i = 0;
while(i<s.length && j < an.length){
if(an == s.charAt[i]){
i++;
j++;
}
else
{
i++;
}
if(j == an.length-1) return an;
}
}
}
public void dfs(char[] haveChars, int index, StringBuilder appender, List<String> res) {
if (index == haveChars.length) {
// youxiao == > res
res.add(appender.toString());
}
char cc = haveChars[index];
// xuan
// buxuan
}