828.统计子串中的唯一字符
题目描述:
我们定义了一个函数 countUniqueChars(s)
来统计字符串 s
中的唯一字符,并返回唯一字符的个数。
例如:s = "LEETCODE"
,则其中 "L"
, "T"
,"C"
,"O"
,"D"
都是唯一字符,因为它们只出现一次,所以 countUniqueChars(s) = 5
。
本题将会给你一个字符串 s
,我们需要返回 countUniqueChars(t)
的总和,其中 t
是 s
的子字符串。输入用例保证返回值为 32 位整数。
注意,某些子字符串可能是重复的,但你统计时也必须算上这些重复的子字符串(也就是说,你必须统计 s
的所有子字符串中的唯一字符)。
数据范围:
$1\le s.len \le 10^5$
$s$ 只包含大写字母。
题解:
dp:
考虑 $dp[i]$ 表示所有以 $i$ 结尾的子字符串的分数。 $dp[i]$ 可以看做 $dp[i-1]$ 的基础之上加上 $s[i]$ ,需要考虑加上 $s[i]$ 之后 $dp[i-1]$ 是怎样变化的。
2916. 子数组不同元素数目的平方和 II 跟这个题目比较类似,但是变化有点不一样。
假设原字符串为 PQABCADE
,需要在该字符串的基础之上加上s[i]='A'
。注意到子串 A,EA,DEA
都会增加 $1$ ,而子串 ADE,CADE,BCADE
都会减少 $1$ 。因此需要记录 $s[i]$ 前一个的位置 $pre1[i]$ ,以及前前一个的位置 $pre2[i]$ 。状态转移方程就为
可以把 $pre1[i], pre2[i]$ 初始化为 $-1$ ,这样的话就统一起来了。
因为这个题目只需要进行区间加,而且只需要记录总数就行了,不用知道每个区间里面都是什么。不像上面那个题目,那个求平方和,需要知道区间内元素的平方和以及元素的和,需要在原来的基础之上加上 $len \times k^2 + 2k\times \sum a_i$ ,不仅需要维护区间平方和=,还要维护区间和。该题只需要维护区间和,所以能够通过状态转移过来,而另一个题目需要使用线段树维护。
当然这个也可以使用线段树维护,但是比较浪费,时间比较慢。
计数原理:
统计每一个 $s[i]$ 对答案的共线,即每个 $s[i]$ 可以作为多少个子数组的唯一元素。
可以预处理出 $left[i]$ 和 $right[i]$ 分别代表 $s[i]$ 作为子数组唯一字符时,能到达的最远的下标。
则子数组左端点有 $i - left[i]$ 个,右端点有 $right[i] - i$ 个,子数组个数就为二者的乘积。
预处理的时候可以使用 $left\_ch[26]$ 表示到达当前下标时每个字符的前一个。
代码:
1 | class Solution |
1 | auto optimize_cpp_stdio = []() |