LeetCode 316. 去除重複字母 java題解

奔跑的廢柴發表於2020-12-15

我除了抄答案什麼都不會。

題目

給你一個字串 s ,請你去除字串中重複的字母,使得每個字母只出現一次。需保證 返回結果的字典序最小(要求不能打亂其他字元的相對位置)。
https://leetcode-cn.com/problems/remove-duplicate-letters/

分析

感覺這題目意思很模糊。
什麼是字典序:哪個字串大取決於兩個字串中 第一個對應不相等的字元 。根據這個規則,任意一個以 a 開頭的字串都大於任意一個以 b 開頭的字串。
按這個來:
解題過程中我們將 最小的字元(a>b>c>…)儘可能的放在前面 。

方法一:貪心 棧

用棧來儲存最終返回的字串,並維持字串的最小字典序。每遇到一個字元,如果這個字元不存在於棧中,就需要將該字元壓入棧中。但在壓入之前,需要先將之後還會出現,並且字典序比當前字元小的棧頂字元移除,然後再將當前字元壓入。

程式碼

class Solution {
    public String removeDuplicateLetters(String s) {
        int[] map=new int[26];
        for(int i=0;i<s.length();i++){
            map[s.charAt(i)-'a']++;
        }
        Deque<Character> stack=new LinkedList<>();
        HashSet<Character> set=new HashSet<>();
        for(int i=0;i<s.length();i++){
            char c=s.charAt(i);
            if(!set.contains(c)){
                //棧頂元素字典序小於當前元素
                while(!stack.isEmpty()&&stack.peekLast()>c&&map[stack.peekLast()-'a']>0){
                    //之後還會出現
                    //移除棧頂
                    set.remove(stack.removeLast());
                }
                //當前元素入棧
                set.add(c);
                stack.addLast(c);
            }
            //當前元素可用數量-1
            map[c-'a']--;
        }
        StringBuilder sb=new StringBuilder(stack.size());
        for(Character c:stack)
            sb.append(c.charValue());
        return sb.toString();
    }
}

複雜度

時間複雜度:O(N)。雖然外迴圈裡面還有一個內迴圈,但內迴圈的次數受棧中剩餘字元總數的限制,因此最終複雜度仍為 O(N)。

空間複雜度:O(1)。看上去空間複雜度像是O(N),但這不對!首先,set中字元不重複,其大小受字母表大小的限制。其次,只有 stack 中不存在的元素才會被壓入,因此 stack 中的元素也唯一。所以最終空間複雜度為O(1)。

結果

在這裡插入圖片描述

相關文章