雙周賽 126。不得不說,這題沒有設置隱藏測資真的是佛心來著,不然通過人數肯定剩一半。

題目

輸入由小寫字母或 ‘?’ 組成的字串 s。

對於一個只由小寫字母組成、長度為 m 的字串 t,定義函數 cost(i) 代表在 [0, i - 1] 的區間內,有多少個字元等於 t[i]。
也就是 t[i] 在 t[0..(i - 1)] 的出現次數。

t 的價值等於所有索引 i 的 cost(i) 總和。

例如 t = “aab”:

  • cost(0) = 0
  • cost(1) = 1
  • cost(2) = 0
  • 因此 “aab” 的價值為 0 + 1 + 0 = 1

你必須將所有 ‘?’ 替換成任意小寫字母,並使得價值最小化

回傳替換所有 ‘?’ 後的字串。如果有多個答案,則回傳字典序最小者。

解法

同一個字元出現越多次,之後的 cost(i) 會產生更大的價值。
而且字典順序要盡可能小,因此填 ‘?’ 的時候,優先選填出現次數最少、且順序最小的字元。

首先遍歷一次 s,計算個字元的出現次數。
再對每個 ‘?’ 分別找出 26 字母中的最佳字元填入。

然後提交答案,就錯了。


試想以下例子:

“abcdefghijklmnopqrstuvwxy??”

a~y 各出現一次,後面跟著兩個問號。
如果照著剛才的找法,會填入 “za”,但正確答案是 “az”。
發現找到的東西是對的,但是填入順序不對。

為避免這種情況,需要把填入的字元先排序一次,再填入就行。

時間複雜度 O(N log N)。
空間複雜度 O(N)。

class Solution:
    def minimizeStringValue(self, s: str) -> str:
        d = Counter(s)
        use = []
        for _ in range(d["?"]):
            cand = "a"
            for c in ascii_lowercase:
                if d[c] < d[cand]:
                    cand = c
            d[cand] += 1
            use.append(cand)
        
        use.sort(reverse=True)
        a = list(s)
        for i, c in enumerate(a):
            if c == "?":
                a[i] = use.pop()
                
        return "".join(a)