leetcode5086:smallest-subsequence-of-distinct-characters

leetcode5086

问题描述

给定一个字符串s,其中只包含小写字母。求s的一个子序列t。要求t包含s中的全部字符。如果答案有多个,输出字典序最小的那个子序列。

解法描述

首先,为s中每个字符打标签,表示该字符是否为其类型中的最后一个字符
其次,从左往右扫描s,让每个字符进栈。进栈过程中满足如下约束:

  • 当栈顶元素为其类型中的最后一个字符,此元素不可弹出
  • 当栈顶元素不是其类型最后一个字符且比当前字符大,那么栈顶元素应该被弹出,因为后面还有这类字符,所以先把它弹出去。这是最重要的贪心。
  • 当栈中已经包含当前字符时,如果当前字符isLast=true,那么栈中的对应字符不可弹出。
import java.util.Arrays;

class Solution {
public String smallestSubsequence(String text) {
    //初始化isLast
    boolean[] isLast = new boolean[text.length()];
    boolean[] had = new boolean[26];
    for (int i = text.length() - 1; i >= 0; i--) {
        int c = text.charAt(i) - 'a';
        if (!had[c]) {
            had[c] = true;
            isLast[i] = true;
        } else {
            isLast[i] = false;
        }
    }
    int[] sta = new int[text.length()];//定义一个栈,栈中存放的是字符的下标
    int si = 0;//定义一个栈顶指针
    int[] indexOf = new int[26];//每类字符在栈中的位置
    Arrays.fill(indexOf, -1);//-1表示字符不在栈中
    for (int i = 0; i < text.length(); i++) {
        char c = text.charAt(i);
        if (indexOf[c - 'a'] != -1) {//栈中已经包含了此字符,则使用最新字符更新之,这个地方很关键
            sta[indexOf[c - 'a']] = i;
            continue;
        }
        while (si > 0) {//当可以弹栈的时候尽量弹栈
            int pos = sta[si - 1];//栈顶元素的下表
            if (isLast[pos]) break;//如果栈顶元素是该类字符中的最后一个,那么不能弹
            char top = text.charAt(pos);//栈顶字符
            if (top < c) break;//如果栈顶字符小于当前字符,停止弹栈
            //否则,执行弹栈
            indexOf[top - 'a'] = -1;
            si--;//弹栈
        }
        sta[si++] = i;//当前元素入栈
        indexOf[c - 'a'] = si - 1;
    }
    //构造答案
    StringBuilder ans = new StringBuilder();
    for (int i = 0; i < si; i++) ans.append(text.charAt(sta[i]));
    return ans.toString();
}
}

猜你喜欢

转载自www.cnblogs.com/weiyinfu/p/10995347.html