目录
计算字符串中同质子字符串的数量 — 题解与思路分析
题目描述
给定一个字符串 s,计算其中所有同质子字符串的数量。
- 同质字符串的定义是:字符串中所有字符都相同。
- 子字符串是字符串中连续的一段字符序列。
由于答案可能非常大,只需返回对 109+710^9 + 7 取余后的结果。
示例:
- 输入:
s = "abbcccaa" - 输出:
13
什么是“同质子字符串”?
所谓“同质子字符串”,就是子字符串中的所有字符都相同。比如:
"a"是同质字符串"bb"是同质字符串"ccc"是同质字符串"ab"不是(不同字符)"aca"不是(不同字符)
题目要求统计字符串中所有可能的同质子字符串个数。
解题分析
关键点
字符串是由多个连续字符组成的,我们要找到所有的连续且字符相同的子字符串。
观察字符串 s,可以将它拆分成若干段连续相同字符的区间:
例如:"abbcccaa"
分段为:"a", "bb", "ccc", "aa"
对于每一段长度为 n 的连续相同字符子串,它产生的同质子字符串数量为:
数量=1+2+3+…+n=n(n+1)2\text{数量} = 1 + 2 + 3 + \ldots + n = \frac{n(n+1)}{2}
这是因为:
- 长度为1的子串有
n个(每个字符单独的子串) - 长度为2的同质子串有
n-1个 - 长度为3的同质子串有
n-2个 - …
- 长度为n的同质子串有
1个
为什么可以拆分成段来计算?
因为不同连续段中的字符不相同,不可能组成同质子字符串跨段边界。
例如 "abbcccaa" 中,"bb" 和 "ccc" 是不同字符段,不可能组合成同质子字符串。
解题方法
思路步骤
- 初始化结果变量
res = 0,以及一个计数器count = 1用来记录当前连续段长度。 - 遍历字符串:
-
- 如果当前字符和前一个字符相同,则
count += 1 - 否则,说明当前连续段结束:
- 如果当前字符和前一个字符相同,则
-
-
- 计算当前段产生的同质子字符串数 count×(count+1)2\frac{count \times (count + 1)}{2},累加到
res - 重置
count = 1
- 计算当前段产生的同质子字符串数 count×(count+1)2\frac{count \times (count + 1)}{2},累加到
-
- 遍历结束后,别忘记加上最后一段的贡献。
- 返回结果对 109+710^9 + 7 取余。
代码实现(Python)
class Solution:
def countHomogenous(self, s: str) -> int:
MOD = 10**9 + 7
res = 0
count = 1
for i in range(1, len(s)):
if s[i] == s[i - 1]:
count += 1
else:
res += count * (count + 1) // 2
count = 1
# 加上最后一段的贡献
res += count * (count + 1) // 2
return res % MOD
复杂度分析
- 时间复杂度:O(n)
只需遍历字符串一次。 - 空间复杂度:O(1)
只使用了常数个额外变量。
示例说明
示例1
输入:"abbcccaa"
分段:
"a"长度为1,贡献 1×(1+1)/2=11 \times (1+1)/2 = 1"bb"长度为2,贡献 2×3/2=32 \times 3/2 = 3"ccc"长度为3,贡献 3×4/2=63 \times 4/2 = 6"aa"长度为2,贡献 2×3/2=32 \times 3/2 = 3
总贡献:
1+3+6+3=131 + 3 + 6 + 3 = 13
输出:13
示例2
输入:"leetcode"
分析:
"l"长度1,贡献1"e"长度1,贡献1"e"长度1,贡献1"t"长度1,贡献1"c"长度1,贡献1"o"长度1,贡献1"d"长度1,贡献1"e"长度1,贡献1
总贡献为8。
解法对比
- 暴力法:遍历所有子字符串,检查是否同质,时间复杂度 O(n3)O(n^3) 或 O(n2)O(n^2),效率极低。
- 本方法:利用连续段统计,时间复杂度仅为 O(n)O(n),极大提升了效率。
总结
本题关键在于识别字符串中连续的相同字符段,并利用数学公式快速计算同质子字符串数量。只需一次遍历即可完成计数,非常高效。此方法在处理类似题目时具有很好的推广价值。
259

被折叠的 条评论
为什么被折叠?



