1. 程式人生 > 實用技巧 >【LeetCode】316.去除重複字母

【LeetCode】316.去除重複字母

題目連結

316. 去除重複字母

題目描述

解題思路

單調棧的應用

本題的解決可以分為兩個過程:

(1) 去重,使得所有元素只出現一次。

(2) 返回字典序最小

先忽略過程2,利用棧這個資料結構實現去重。去重的原理就是利用isUsed陣列標記該元素是否在棧中出現,如果是則跳過,否則在棧中加入該元素。

如何讓棧中存在的字串組成的字典序最小呢?

這就是單調棧的應用,但是必須要注意的一點就是:當棧頂元素大於要push進去的元素時

stk.peek() > c 時才會 pop 元素,其實這時候應該分兩種情況:

  • 如果 st.peek() 這個字元之後還會出現,那麼可以把它 pop 出去,反正後面還有嘛,後面再 push 到棧裡,剛好符合字典序的要求。

  • 如果 st.peek() 這個字元之後不會出現了,前面也說了棧中不會存在重複的元素,那麼就不能把它 pop 出去,否則你就永遠失去了這個字元。

AC程式碼

//1.利用棧實現去重
class Solution {
    public String removeDuplicateLetters(String s) {
        Stack<Character> st = new Stack();
        StringBuffer ans = new StringBuffer();
        boolean isUsed[] = new boolean[26];
        char[] sChar = s.toCharArray();
        int charCount[] = new int[26];
        for(char i : sChar){
            if(isUsed[i-'a']) continue;
            st.push(i);
            isUsed[i-'a'] = true;
        }
        while(!st.isEmpty()) ans.append(st.pop());
        return ans.reverse().toString();
    }
}
//2.完整程式碼
class Solution {
    public String removeDuplicateLetters(String s) {
        Stack<Character> st = new Stack();
        StringBuffer ans = new StringBuffer();
        //根據isUsed陣列實現棧中元素去重
        boolean isUsed[] = new boolean[26];
        char[] sChar = s.toCharArray();
        int charCount[] = new int[26];
        //記錄每個字元出現的次數
        for(char i : sChar) charCount[i-'a']++;
        for(char i : sChar){
            charCount[i-'a']--;
            if(isUsed[i-'a']) continue;
            while(!st.isEmpty() && st.peek() > i && charCount[st.peek()-'a'] > 0){
                isUsed[st.peek()-'a'] = false;
                st.pop();
            }
            st.push(i);
            isUsed[i-'a'] = true;
        }
        while(!st.isEmpty()) ans.append(st.pop());
        return ans.reverse().toString();
    }
}