定义个函数 countUniqueChars(s) 为s中仅仅出现一次的字母的个数
给一个字符串,求这个字符串所有的子串的countUniqueChars之和。
len <= 1e5
暴力枚举不可行。
这个题目想了好久,想了滑动窗口,想了dp计数,发现要么行不通,要么看错了题。
其实这个题反过来考虑,每个字母对结果的贡献,就可以解决了。
考虑一个字母什么时候可以成为唯一的字母,就是它向左向右扩展时候遇到第一个和自己相同的字母的时候
比如BABBBBACCCAB
那么第二个字母'A'有贡献的时候即为BA (BBBBACCC) AB,
贡献即为左边字母的个数+1 乘以 右边字母个数+1
即为
BBBBA BBBA BBA BA A
BBBBAC BBBAC BBAC BAC AC
BBBBACC BBBACC BBACC BACC ACC
BBBBACCC BBBACCC BBACCC BACCC ACCC
也就是4 * 5 = 20
public int uniqueLetterString(String s) {
char[] ch = s.toCharArray();
int len = s.length();
long res = 0;
int mod = 10_0000_0007;
int[] left = new int[len];
int[] right = new int[len];
int[] letter = new int[26];
Arrays.fill(letter, -1);
for (int i = 0; i < len; i++) {
//在它左边和他字母相同最近的位置
left[i] = letter[ch[i] - 'A'];
letter[ch[i] - 'A'] = i;
}
Arrays.fill(letter, len);
for (int i = len - 1; i >= 0; i--) {
//在它右边和他字母相同最近的位置
right[i] = letter[ch[i] - 'A'];
letter[ch[i] - 'A'] = i;
}
//计算每个字母对结果的贡献,也就是计算这个字母什么时候可以成为一个uniqueLetter
for (int i = 0; i < len; i++) {
int l = i - left[i];
int r = right[i] - i;
res += l * r;
res %= mod;
}
return (int) res;
}