唯一字符常规乘法原理在统计子串中的应用
我们定义了一个函数countUniqueChars(s)来计算字符串s中的唯一字符数,并返回唯一字符数。
比如:s = "LEETCODE ",其中" l "、" t "、" c "、" o "、" d "是唯一字符,因为只出现一次,所以countUniqueChars(s) = 5。
这个问题会给你一个字符串S,我们需要返回countUniqueChars(t)的和,其中t是S的子串,输入用例保证返回值是32位整数。
请注意,有些子字符串可能是重复的,但是您还必须对这些重复的子字符串进行计数(也就是说,您必须对S的所有子字符串中的唯一字符进行计数)。
示例1:
Enter: 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:
Enter: s = "LEETCODE "
产量:92
复制代码
提示:
一个
s只包含大写的英文字符。
模拟+乘法原理
原问题是求所有子阵列的唯一字符之和,可以等价于求每个s[i]s[i]s[i]对答案的贡献,即每个s[I]s[I]s[I]s[I]可以充当多少个子阵列的唯一元素。
假设我们可以分别预处理两个数组L和R,这两个数组表示当s[i]s[i]s[i]是子数组的唯一字符时可以到达的最远端:
L[i] = a表示下标aaa为s[i]s[i]s[i]时最左边界可以是子数组的唯一字符,也就是s[i]s[i]s[i]左边第一个与s[i]s[i]相同的位置(不存在则为A =
R[i] = b表示跳转表bbb为s[i]s[i]s[i]时最右边界可以作为子数组的唯一字符,即S[I]S[I]S[I]S[I]S[I]右边第一个位置(如果不存在,则为b。
子阵列左端点数为(ia) (i-a) (ia),右端点数为(bi) (b-i) (bi)。根据乘法原理,子阵的个数是两者的乘积。
l和r只需要使用遍历计数进行预处理。
Java代码:
类别解决方案{
public int uniqueLetterString(String s){
char[]cs = s . tochararray();
int n = cs.length,ans = 0;
int[] l = new int[n],r = new int[n];
int[]CNTs = new int[26];
Arrays.fill(cnts,-1);
for(int I = 0;I < n;i++) {
int u = cs[I]-' A ';
l[I]= CNTs[u];
CNTs[u]= I;
}
Arrays.fill(cnts,n);
for(int I = n-1;I > = 0;我- ) {
int u = cs[I]-' A ';
r[I]= CNTs[u];
CNTs[u]= I;
}
for(int I = 0;I < n;i++)ans+=(I-l[I])*(r[I]-I);
返回ans
}
}
复制代码
类型脚本代码:
function uniqueLetterString(s:string):number {
设n = s.length,ans = 0
const l =新数组(n),r =新数组(n)
const cnts =新数组(26)。填充(-1)
for(设I = 0;I < n;i++) {
const u = s.charCodeAt(i) - 65
l[i] = cnts[u]
cnts[u] = i
}
cnts.fill(n)
for(设I = n-1;I > = 0;我- ) {
const u = s.charCodeAt(i) - 65
r[i] = cnts[u]
cnts[u] = i
}
for(设I = 0;I < n;i++) ans += (i - l[i]) * (r[i] - i)
返回答案
};
复制代码
时间复杂度:O(n)O(n)O(n)
空间复杂度:O(n)O(n)O(n)
Node.js工程师养成计划download:http://www.51xuebc.com/thread-447-1-1.html