828. 统计子串中的唯一字符
难度
困难
我们定义了一个函数 countUniqueChars(s) 来统计字符串 s 中的唯一字符,并返回唯一字符的个数。
例如:s = "LEETCODE" ,则其中 "L", "T","C","O","D" 都是唯一字符,因为它们只出现一次,所以 countUniqueChars(s) = 5 。
本题将会给你一个字符串 s ,我们需要返回 countUniqueChars(t) 的总和,其中 t 是 s 的子字符串。输入用例保证返回值为 32 位整数。
注意,某些子字符串可能是重复的,但你统计时也必须算上这些重复的子字符串(也就是说,你必须统计 s 的所有子字符串中的唯一字符)。
示例 1:
输入: s = "ABC"
输出: 10
解释: 所有可能的子串为:"A","B","C","AB","BC" 和 "ABC"。
其中,每一个子串都由独特字符构成。
所以其长度总和为:1 + 1 + 1 + 2 + 2 + 3 = 10
示例 2:
输入: s = "ABA"
输出: 8
解释: 除了 countUniqueChars("ABA") = 1 之外,其余与示例 1 相同。
示例 3:
输入:s = "LEETCODE"
输出:92
提示:
1 <= s.length <= 10^5
s 只包含大写英文字符
思路:此题与前面的子数组的最小值之和类似,不过不需要用到单调栈
对于每一个字符,我们分别向左和向右找第一个和其相同的字符,计算该字符对答案的贡献值,也就是说对于数组下标为 i的元素 我们需要找到 l,分别为其左右第一个相同字符的位置,此处我们可以将 l,i,r的问题转换成 l,l,i的问题,也就是说我们每遍历到一个字符时,取出记录的其上次出现和上上次出现的位置,其中上次出现对应上述思路中的i,上上次出现对应l,那么本次出现就对应r,在遍历到某个字符的时候取出位置计算并且更新值
运用此种思路需要注意,有的字符并不一定出现了三次或者从字符最后一次出现到字符串尾端其也没有出现,所以最后需要假设每个字符都在末尾出现过一次,得到最终答案
AC代码如下
class Solution { public: int uniqueLetterString(string s) { //统计子串中唯一的字符 我们考虑每个字母对包含该字母且唯一的子字符串 int res=0,n=s.size(); vector<int> p(26,-1); vector<int> pp(26,-1); int pos; for(int i=0;i<n;i++){ //每遍历到一个字符,分别向左和向右寻找第一个和该字符相同的字符 pos=s[i]-'A'; res+=(p[pos]-pp[pos])*(i-p[pos]); pp[pos]=p[pos]; p[pos]=i; } for(int i=0;i<26;i++) res+=(n-p[i])*(p[i]-pp[i]); return res; } };