统计同构子字符串的数目
题目描述
给你一个字符串 s
,返回 s
中 同构子字符串 的数目。由于答案可能很大,只需返回对 109 + 7 取余 后的结果。
同构字符串 的定义为:如果一个字符串中的所有字符都相同,那么该字符串就是同构字符串。
子字符串 是字符串中的一个连续字符序列。
示例 1
输入:s = “abbcccaa”
输出:13
解释:同构子字符串如下所列:
“a” 出现 3 次。
“aa” 出现 1 次。
“b” 出现 2 次。
“bb” 出现 1 次。
“c” 出现 3 次。
“cc” 出现 2 次。
“ccc” 出现 1 次。
3 + 1 + 2 + 1 + 3 + 2 + 1 = 13
示例 2
输入:s = “xy”
输出:2
解释:同构子字符串是 “x” 和 “y” 。
示例 3
输入:s = “zzzzz”
输出:15
提示
- 1 <= s.length <= 105
- s 由小写字符串组成
算法一:模拟+数学
思路
- 首先,单个字符一定是同构字符串,因此
res
一开始被赋值为len
; - 接下来,遍历每个字符,判断它与随后的字符是否会构成同构字符串。如果当前字符
s[i] == s[j]
,说明存在同构字符串,否则不存在,继续判断下一个字符。那么如何计算同构字符串的个数呢? - 我们先看一个例子: “cccc” ,其中包含的同构字符串有:c:4, cc:3, ccc:2, cccc:1,不难发现,假设连续字符串的个数为
cnt
,那么同构字符串的个数为:cnt * (cnt + 1) / 2
,由于单个字符串(即 ‘c’ 的情况),我们一开始就计入了,因此同构字符串的个数为:cnt * ( cnt - 1) / 2
。 - 在实现中,我令
ans
从 0 开始,也就是说,如果 “cc” ,则ans = 1
,那么此时的同构字符串个数为:ans * (ans + 1) / 2
。至于为什么令ans
的初值为0,方便判断此时是否存在连续字符串。
收获
- 此题不难,刚好昨天做的题运用了数学思想,因此很快想到了
i*(i+1)/2
。 - 一开始不通过的原因是:
mod=1e9+7
,我写成了mod=10e9+7
。
算法情况
- 时间复杂度:O(n),其中 n 为字符串长度。
- 空间复杂度:O(1)
代码
class Solution {
public:
int countHomogenous(string s) {
int len = s.size();
long long mod = 1e9 + 7;
// 单个字符即为一个同构字符串
long long res = (long long)len;
for(int i=0; i<len; ++i){
int ans = 0;
for(int j=i+1; j<len; ++j){
if(s[j] == s[i]) ans ++;
else break;
}
if(ans){
res += (long long)(ans+1) * ans / 2;
i += ans;
}
}
return res%mod;
}
};