字符串专题
总结关于字符串的常用算法板子
字符串中子串个数
子串可重叠
int f(const std::string& str, const std::string& sub)
{
int num = 0;
for (size_t i = 0; (i = str.find(sub, i)) != std::string::npos; num++, i++);
return num;
}
子串不可重叠
int f(const std::string& str, const std::string& sub)
{
int num = 0;
size_t len = sub.length();
if (len == 0)len=1;//应付空子串调用
for (size_t i=0; (i=str.find(sub,i)) != std::string::npos; num++, i+=len);
return num;
}
不同的子序列
[problem description]
给定一个字符串 s
,计算 s
的 不同非空子序列 的个数。因为结果可能很大,所以返回答案需要对 10^9 + 7
取余 。
字符串的 子序列 是经由原字符串删除一些(也可能不删除)字符但不改变剩余字符相对位置的一个新字符串。
- 例如,
"ace"
是"abcde"
的一个子序列,但"aec"
不是。
[input]
s="aba"
[output]
6
[datas]
1 <= s.length <= 2000
s
仅由小写英文字母组成
[solved]
dp[i]为前i个字符可以组成的不同的子序列,则有
dp[i] = dp[i - 1] + newCount - repeatCoun
newCount
为加上 s[i]
后新增的子序列个数,repeatCount
为重复的子序列个数
我们只需要计算 newCount
和 repeatCount
即可
newCount
的值比较好计算,就是 dp[i - 1]
。
然后我们计算repeatCount,我们观察遍历到的第二个字符b,出现重复的序列为b和ab,而这两个序列正好是上一次添加b(也就是第②步)的时候新增的两个序列。于是我们可以使用数组preCount来记录上一次该字符新增的个数,该个数就是repeatCount。
由于dp[i]仅和dp[i-1]有关,我们可以滚动存储。
[python]
class Solution:
def distinctSubseqII(self, s: str) -> int:
mod=10**9+7
d=defaultdict(int)
n=len(s)
cur=1
for i in range(0,n):
pre=cur
cur=((cur+pre)%mod-d[s[i]]+mod)%mod
d[s[i]]=pre
return (cur-1+mod)%mod