前往
大廳
主題

LeetCode - 0828. Count Unique Characters of All Substrings of a Given String 解題心得

Not In My Back Yard | 2024-05-22 12:00:01 | 巴幣 0 | 人氣 45

題目連結:


題目意譯:
定義一個函式 countUniqueChars(s),其會回傳 s 中只出現一次的字元種類數。

例如說,當 s = "LEETCODE" 時呼叫 countUniqueChars(s),則在當中 "L" 、 "T" 、 "C" 、 "O" 、 "D" 只出現一次,因此 countUniqueChars(s) = 5。

給定一個字串 s,回傳 countUniqueChars(t) 的總和,其中 t 為 s 的子字串。測試資料之生成滿足答案必定可以被一個 32 位元有號整數所容納。

注意到有些子字串可能會重複出現,而在本題你對於這些重複出現的子字串也需要一併計算。

限制:
1 ≦ s.length ≦ 10 ^ 5
s 只由大寫英文字母組成。



範例測資:
範例 1:
輸入: s = "ABC"
輸出: 10
解釋: 所有可能的子字串為: "A" 、 "B" 、 "C" 、 "AB" 、 "BC" 和 "ABC"。
每一個子字串只由相異字元組成。
所有子字串的長度總和為 1 + 1 + 1 + 2 + 2 + 3 = 10

範例 2:
輸入: s = "ABA"
輸出: 8
解釋: 跟範例 1 基本一樣,除了 countUniqueChars("ABA") = 1。

範例 3:
輸入: s = "LEETCODE"
輸出: 92


解題思維:
這題類似,只要考慮每個字元 s[i] 在所有包含 s[i] 的子字串中有多少個是只出現一次的。將這些個數加總即為所求。



(令 n = s.length)
可以看到 s[i] 會出現在 (i + 1) × (n - i) 個子字串中,因為「左邊」可以從 s[0] ~ s[i] 中隨便選一個作為開頭、「右邊」則可以從 s[i] ~ s[n - 1] 中隨便選一個作為結尾。

而其中會有 (i - L(i)) × (R(i) - i) 個子字串滿足 s[i] 只出現一次,而當中的 L(i) 滿足 L(i) < i 、 s[L(i)] == s[i] 且 L(i) 盡可能地大(即 s[L(i)] 是 s[i]「前一次」出現的位置);R(i) > i 、 s[R(i)] == s[i] 且 R(i) 盡可能地小(即 s[L(i)] 是 s[i]「下一次」出現的位置)。

而如果沒有「前一次」,則定義 L(i) 為 -1。因為這樣 L(i) + 1 剛好會指向 s[0];同理如果沒有「下一次」,則定義 R(i) 為 n。因為這樣 R(i) - 1 剛好會指到 s[n - 1]。

可以看到對於一個 s[i] 而言要「同時」求 L(i) 和 R(i) 並不容易。但是如果我們一次如果只求一邊,例如只求 L(i),則我們可以用一個陣列來紀錄每一種字元「上一次」出現於何處。這樣便可以藉由從左至右掃過 s 求出每一個位置 i 的 L(i) 值;同理,也可以藉由從右至左掃過 s 來得到每一個位置 i 的 R(i) 值。

最後根據一開始的想法算出所有 (i - L(i)) × (R(i) - i) 之值加總即是所求。




此次分享到此為止,如有任何更加簡潔的想法或是有說明不清楚之地方,也煩請各位大大撥冗討論。

創作回應

更多創作