316. 去除重复字母
1081. 不同字符的最小子序列
给你一个字符串 s ,请你去除字符串中重复的字母,使得每个字母只出现一次。需保证 返回结果的字典序最小(要求不能打乱其他字符的相对位置)。

注意:该题与 1081 https://leetcode-cn.com/problems/smallest-subsequence-of-distinct-characters 相同

示例 1:

输入:s = "bcabc"
输出:"abc"
示例 2:

输入:s = "cbacdcbc"
输出:"acdb"

运行结果
图片说明
图片说明
解题思路
利用栈记录结果
去重的入栈:已入栈跳过。当出现栈顶元素大于当前元素时判断,如果后续还有则出栈,后续再入,否则跳过
所以需要辅助数组来记录是否已经入栈,以及后续还有几个
26的数组是存字母到a的距离
256是直接存字母的ascll码
时间换空间
java代码

class Solution {
    public String removeDuplicateLetters(String s) {
        int[] count=new int[26];//记录字符数目-26个英文字母
        boolean[] inStack=new boolean[26];//记录是否入栈
        Stack<Character> stack=new Stack<>();
        char[] chars=s.toCharArray();
        //记录字母的数目
        for(char c:chars){
            count[c-'a']++;
        }
        for(char c : chars){
            //数目减一
            count[c-'a']--;
            //已有则去重
            if(inStack[c-'a']) continue;
            //栈顶较小时
            while( !stack.isEmpty() && stack.peek() > c){
                //后续没有则跳出。必须有,不然会死循环
                if(count[stack.peek() - 'a']==0) break;
                //后续还有则弹出
                inStack[stack.pop()-'a']=false;
            }
            //入栈,改标志位
            stack.push(c);
            inStack[c-'a']=true;
        }
        //记录结果集
        StringBuffer sb=new StringBuffer();
        while(!stack.isEmpty()){
            sb.append(stack.pop());
        }
        return sb.reverse().toString();
    }
}

class Solution {
    public String smallestSubsequence(String s) {
        int[] count=new int[256];
        boolean[] instack=new boolean[256];
        Stack<Character> stk=new Stack<>();
        char[] chars=s.toCharArray();
        //记录字母的数目
        for(char c: chars){
            count[c]++;
        }
        for(char c : chars){
            //遍历减1
            count[c]--;
            //已入栈去重
            if(instack[c]) continue;
            //若栈顶过大
            while( !stk.isEmpty() && stk.peek() > c){
                //若后续没有则跳过
                if(count[stk.peek()]==0) break;
                //否则出栈,改标志
                instack[stk.pop()]=false;
            }
            //入栈改标志
            stk.push(c);
            instack[c]=true;
        }
        //记录结果
        StringBuilder sb=new StringBuilder();
        while(!stk.isEmpty()){
            sb.append(stk.pop());
        }
        return sb.reverse().toString();
    }
}