好多牛牛
题目描述
给出一个字符串S,牛牛想知道这个字符串有多少个子序列等于"niuniu"
子序列可以通过在原串上删除任意个字符(包括0个字符和全部字符)得到。
为了防止答案过大,答案对1e9+7取模
示例输入
“niuniniu”
输出
3
说明
删除第4,5个字符可以得到"niuniu"
删除第5,6个字符可以得到"niuniu"
删除第6,7个字符可以得到"niuniu"
解析
本题目使用动态规划的算法求解。
案例中,在niuniniu中找模式串niuniu,我们在输入串中匹配模式串,模式串中每个字符的匹配次数只和前一个字符有关,因为只有出现了前一个字符,后一个字符才能匹配成功,除了第一个字符(出现一次匹配一次,因为没有前缀)。
输入\模式串匹配次数 | n | i | u | n | i | u |
---|---|---|---|---|---|---|
null | 0 | 0 | 0 | 0 | 0 | 0 |
n | 1 | 0 | 0 | 0 | 0 | 0 |
i | 1 | 1 | 0 | 0 | 0 | 0 |
u | 1 | 1 | 1 | 0 | 0 | 0 |
n | 2 | 1 | 1 | 1 | 0 | 0 |
i | 2 | 3 | 1 | 1 | 1 | 0 |
n | 3 | 3 | 1 | 2 | 1 | 0 |
i | 3 | 6 | 1 | 2 | 3 | 0 |
u | 3 | 6 | 7 | 2 | 3 | 3 |
从上表可以看出,每输入一个字符,对应模式串的子串匹配量就增加前一个字符的匹配量,用一个简单的例子表示:
在aaabb中匹配模式串ab,当输入到 b 的时候,a 已经输入了 3 次,因此模式串 ab 的匹配次数要加上模式串前一个字符 a 的匹配次数;当输入第二个 b 的时候,再加上模式串中前一个字符的匹配次数,因此ab一共匹配了6次。
案例中,当输入最后一个u的时候,子串ni已经匹配了6次,即是说,在新输入的u前面,有6个ni可以和新的u组成niu,因此,模式串niu的匹配次数 1(原有)+6=7;子串niuni匹配了3次,模式串niuniu的匹配次数 0+3=3 。
设一个长度为模式串pattern.size()+1的数组dp[],为了统一计算,即每个字符只和前一个字符匹配次数有关,设 dp[0] = 1,这样每次出现模式串的第一个字符,也可以计算dp[1]+=dp[0],即自增。
const int mod = 1e9+7;
class Solution {
public:
int solve(string s) {
// write code here
string pattern = "niuniu";
vector<int> dp(pattern.size()+1, 0);
dp[0] = 1;
for(char &c : s)
for(int i = 0; i < pat.size(); i++)
if(pattern[i] == c)
dp[i+1] = (dp[i+1] + dp[i]) % mod;
return dp[pattern.size()];
}
};