Let's define a function countUniqueChars(s)
that returns the number of unique characters on s
.
- For example, calling
countUniqueChars(s)
ifs = "LEETCODE"
then"L"
,"T"
,"C"
,"O"
,"D"
are the unique characters since they appear only once ins
, thereforecountUniqueChars(s) = 5
.
Given a string s
, return the sum of countUniqueChars(t)
where t
is a substring of s
.
Notice that some substrings can be repeated so in this case you have to count the repeated ones too.
Example 1:
Input: s = "ABC" Output: 10 Explanation: All possible substrings are: "A","B","C","AB","BC" and "ABC". Evey substring is composed with only unique letters. Sum of lengths of all substring is 1 + 1 + 1 + 2 + 2 + 3 = 10
Example 2:
Input: s = "ABA"
Output: 8
Explanation: The same as example 1, except countUniqueChars
("ABA") = 1.
Example 3:
Input: s = "LEETCODE" Output: 92
Constraints:
1 <= s.length <= 105
s
consists of uppercase English letters only.
题目首先定义了一个函数 countUniqueChars(s),该
函数功能是返回输入字符串s中的单一字符的个数,即在字符串s中只出现一次的字符的个数。现在给定一个字符串,要求返回给定字符串的所有子字符串中的单一字符个数的总和,即对所有子字符串t都调用countUniqueChars(t)
函数,把所有返回值加在一起。另外,子字符串中可能存在重复,但是也要分别计算。
直观方法是找出所有子字符串,对每个子字符串挨个统计单一字符的个数,很显然计算量是巨大。这里我们要统计的是所有字符串中单一字符的个数,其实换角度看问题,最终所有子字符串中单一字符的总个数跟以每个字符为单一字符(只出现一次)的子字符串的总个数是相同的(有点类似LeetCode 2104. Sum of Subarray Ranges)。于是题目就变成了如何计算以每一个字符为单一字符的子字符串个数。
对于长度为n的输入字符串的第i个字符,如果它左边出现相同字符的位置是j(左边到头都没有相同字符j=-1),如果它右边出现相同字符的位置为k(右边都尾都没有相同字符k=n),那么以第i个字符为单一字符的子字符串个数就为(i - j)* (k - i)。实现代码时,我们可以从左到右扫描一遍数组,统计每个字符的左边出现相同字符的位置,再从右到左扫描一遍数组,统计每个字符的右边出现相同字符的位置,然后就可以计算每个字符作为单一字符的子字符串个数,最后个数总和就是所有子字符串中的单一字符个数的总和。
class Solution:
def uniqueLetterString(self, s: str) -> int:
res = 0
n = len(s)
left, right = [0] * n, [0] * n
pos = {}
for i, c in enumerate(s):
if c in pos:
left[i] = pos[c]
else:
left[i] = -1
pos[c] = i
pos = {}
for i in range(n - 1, -1, -1):
if s[i] in pos:
right[i] = pos[s[i]]
else:
right[i] = n
pos[s[i]] = i
for i in range(n):
res += (i - left[i]) * (right[i] - i)
return res