leetcode5086:smallest-subsequence-of-distinct-characters

leetcode5086java

問題描述

給定一個字符串s,其中只包含小寫字母。求s的一個子序列t。要求t包含s中的所有字符。若是答案有多個,輸出字典序最小的那個子序列。app

解法描述

首先,爲s中每一個字符打標籤,表示該字符是否爲其類型中的最後一個字符
其次,從左往右掃描s,讓每一個字符進棧。進棧過程當中知足以下約束:ui

  • 當棧頂元素爲其類型中的最後一個字符,此元素不可彈出
  • 當棧頂元素不是其類型最後一個字符且比當前字符大,那麼棧頂元素應該被彈出,由於後面還有這類字符,因此先把它彈出去。這是最重要的貪心。
  • 當棧中已經包含當前字符時,若是當前字符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();
}
}
本站公眾號
   歡迎關注本站公眾號,獲取更多信息