316. 去除重复字母

  1. 定义泛型为字符的栈
  2. 维护一个计数器数组,大小为256,用来记录每一个字符的数量,并把输入字符串中所有字符统计一遍
  3. 维护一个布尔数组,大小256,记录栈中是否存在某个字符
  4. 循环遍历每一个字符
  5. 当前字符对应的计数减一
  6. 如果已经存在当前字符,直接跳过
  7. 在插入栈之前,循环和之前的元素(栈顶元素)比较大小,如果字典序比前面小,pop前面元素
  8. 若当前字符之后,不存在栈顶元素,则停止pop
  9. 如果之后还有,则可以pop
  10. 如果不存在当前字符,则插入栈顶并标记为存在
  11. StringBuilder把栈中所有元素加进去
  12. 最后返回,因为栈是反着插入元素,需要reverse一下
public 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 字符,所以大小 256 够用了
    boolean[] inStack = new boolean[256];
    for(char c : s.toCharArray()){
        //每遍历一个字符,都将对应的计数减一
        count[c]--;

        //如果已经存在当前字符,直接跳过
        if(inStack[c]) continue;

        // 插入之前,和之前的元素比较一下大小
        // 如果字典序比前面的小,pop 前面的元素
        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.isEmpty()){
        sb.append(stk.pop());
    }

    //栈中元素插入顺序是反的,需要 reverse 一下
    return sb.reverse().toString();
}

1081. 不同字符的最小子序列

和316同题,代码一样。