题目
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();
}
}