【LeetCode】1081. Smallest Subsequence of Distinct Characters

题目

Return the lexicographically smallest subsequence of text that contains all the distinct characters of text exactly once.

Example 1:
Input: "cdadabcc"
Output: "adbc"

Example 2:
Input: "abcd"
Output: "abcd"

Example 3:
Input: "ecbacba"
Output: "eacb"

Example 4:
Input: "leetcode"
Output: "letcod"
 
Note:
1 <= text.length <= 1000
text consists of lowercase English letters.

题意

给定一个字符串找出其中字典序(之和)最小的子序列,并且这个子序列一定要包含原字符串中所有出现过的字符,子序列中每个字母只能出现一次。

代码

本人做这道题的时候第一遍就过了,有点惊讶,写完总觉得还有情况没考虑到,提交之后通过了仔细想一下确实是没问题的。具体思路如下:

  • 整体思路是遍历字符串时,比较当前字符串和已经追加到结果字符串中的字符(字符串从后往前遍历),如果①结果字符串不为空②当前字符没在结果字符串中出现过且③当前字符串比结果字符串中的尾部字符小且④结果字符串末尾的字符后面还会再出现,则将结果字符串的末尾字符串移除,否则不移除,然后将当前字符串追加到结果字符串尾部
  • 通过思路分析,实现过程中的结果字符串先用栈保存更方便处理,将某个字符追加到结果字符串末尾就进行入栈,将结果字符串末尾字符移除就进行出栈
  • 对于判断字符串在后续是否会再次出现,本人使用了一个数组maxIndexes,用来记录每个字符串出现的最后位置,用当前字符串位置与maxIndexes[ch]对比就可以知道后面是否会再次出现字符ch
  • 另外需要使用一个数组used来记录某个字符是否已经在结果字符串中,注意每次将字符加入结果字符串时需要将used对应位置的值置为true,每次移除是置位false

具体代码如下

import java.util.Stack;

class Solution {
    public String smallestSubsequence(String text) {
        int[] maxIndexes = new int[26];
        boolean[] used = new boolean[26];
        Stack<Character> stack = new Stack<Character>();

        for (int i = 0; i < text.length(); i++) {
            char ch = text.charAt(i);
            maxIndexes[ch - 'a'] = i;
        }

        for (int i = 0; i < text.length(); i++) {
            char ch = text.charAt(i);

            if (used[ch - 'a'] == false){
                while (!stack.empty()){
                    char tmpCh = stack.peek(); // 取出末尾字符,不出栈
                    if (maxIndexes[tmpCh - 'a'] > i && ch < tmpCh){
                        stack.pop(); // 末尾字符出栈
                        used[tmpCh - 'a'] = false;
                    }else {
                        break;
                    }
                }
                stack.push(ch);
                used[ch - 'a'] = true;
            }
        }

        StringBuilder sb = new StringBuilder();
        for (Character character : stack) {
            sb.append(character);
        }

        return sb.toString();
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

WGeeker

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值