我们定义了一个函数
countUniqueChars(s)
来统计字符串s
中的唯一字符,并返回唯一字符的个数。例如:
s = "LEETCODE"
,则其中"L"
,"T"
,"C"
,"O"
,"D"
都是唯一字符,因为它们只出现一次,所以countUniqueChars(s) = 5
。本题将会给你一个字符串
s
,我们需要返回countUniqueChars(t)
的总和,其中t
是s
的子字符串。输入用例保证返回值为 32 位整数。注意,某些子字符串可能是重复的,但你统计时也必须算上这些重复的子字符串(也就是说,你必须统计
s
的所有子字符串中的唯一字符)。
输入: s = “ABC”
输出: 10
解释: 所有可能的子串为:“A”,“B”,“C”,“AB”,“BC” 和 “ABC”。
其中,每一个子串都由独特字符构成。
所以其长度总和为:1 + 1 + 1 + 2 + 2 + 3 = 10
输入: s = “ABA”
输出: 8
解释: 除了 countUniqueChars(“ABA”) = 1 之外,其余与示例 1 相同。
输入:s = “LEETCODE”
输出:92
提示:
1 <= s.length <= 10^5
s
只包含大写英文字符
以s=BCADEAFGA 为例,当遍历到最后一个 A 时:
countUniqueChars
值为 1;countUniqueChars
值都会增加 1;countUniqueChars
值都会减少 1;countUniqueChars
值。据此,我们在从左往右遍历 s 的同时,对每个字母 s[i] 记录其上一次出现的下标 last 0 [ s [ i ] ] \textit{last}_0[s[i]] last0[s[i]] 和上上一次出现的下标 last 1 [ s [ i ] ] \textit{last}_1[s[i]] last1[s[i]]。通过上面的例子,我们可以算出从「以 s[i−1] 结尾的子串」到「以 s[i]] 结尾的子串」,countUniqueChars 值的和,增加/减少了多少:
二者相加,总的变化量为: i − 2 ⋅ l a s t 0 [ s [ i ] ] + l a s t 1 [ s [ i ] ] i−2⋅last_0[s[i]]+last_1[s[i]] i−2⋅last0[s[i]]+last1[s[i]]
特别地,如果 last 0 [ s [ i ] ] \textit{last}_0[s[i]] last0[s[i]]或 last 1 [ s [ i ] ] \textit{last}_1[s[i]] last1[s[i]]不存在,可以视作 −1,从而保证上式的正确性。
class Solution:
def uniqueLetterString(self, s: str) -> int:
result = total = 0
last0, last1 = {}, {}
for i, c in enumerate(s):
total += i - 2 * last0.get(c, -1) + last1.get(c, -1)
result += total
last1[c] = last0.get(c, -1)
last0[c] = i
return result
复杂度分析
时间复杂度:O(n),其中 n 为 s 的长度。
空间复杂度: O ( ∣ Σ ∣ ) O(|\Sigma|) O(∣Σ∣),其中 ∣ Σ ∣ |\Sigma| ∣Σ∣ 为字符集合的大小,本题中字符均为大写字母,所以 ∣ Σ ∣ |\Sigma| ∣Σ∣=26。
参考:
1.https://leetcode.cn/problems/count-unique-characters-of-all-substrings-of-a-given-string/solution/by-muse-77-v7cs/
2.https://leetcode.cn/problems/count-unique-characters-of-all-substrings-of-a-given-string/solution/by-endlesscheng-ko4z/