leetcode1081 (不同字符的最小子序列) | 刷题打卡

258 阅读1分钟

掘金团队号上线,助你 Offer 临门! 点击查看详情

一、题目描述:
返回 字符串s中 字典序最小的子序列,该子序列包含 s 的所有不同字符,且只包含一次, 且1 <= s.length <= 1000 ,s 由小写英文字母组成

二、思路分析: 根据示例可发现规律,

  1. 如果一个字母只出现一次那么必定被选取到子序列中
  2. 按照字母升序排列的子串肯定是字典序最小的。
  3. 如果一个字母被选取且后续的字母有相同的,那么这个字母会被丢弃,因为如果后面存在比这个字母要小的字母,那么选择相同的字母字典序会更小,所以当前字母会被丢弃
  4. 考虑使用单调栈,先进来的字母可能会被移除,符合先进后出的原则
  5. 如果一个字母已经在栈中,那么如果后续有相同的字母,那么这个相同的字母会被丢弃,因为要保持不能存在重复的字母这条原则,且如果让这个相同的字母入栈,让已经在栈中的字母丢弃,则会导致当前子串的字典序不会更小,所以舍弃这个相同的字母会更好。

三、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();
   }     

四、总结:
更多的是查看规律问题,善于使用其他数据结构解决复杂问题,栈,队列等。