给定一个全部由小写英文字母组成的字符串,允许你至多删掉其中 3 个字符,结果可能有多少种不同的字符串?
输入格式:
输入在一行中给出全部由小写英文字母组成的、长度在区间 [4, 106] 内的字符串。
输出格式:
在一行中输出至多删掉其中 3 个字符后不同字符串的个数。
输入样例:
ababcc
输出样例:
25
提示:
删掉 0 个字符得到 “ababcc”。
删掉 1 个字符得到 “babcc”, “aabcc”, “abbcc”, “abacc” 和 “ababc”。
删掉 2 个字符得到 “abcc”, “bbcc”, “bacc”, “babc”, “aacc”, “aabc”, “abbc”, “abac” 和 “abab”。
删掉 3 个字符得到 “abc”, “bcc”, “acc”, “bbc”, “bac”, “bab”, “aac”, “aab”, “abb” 和 “aba”。
分析:一个简单的动态规划题~使用dp[i][j]表示前i个字符串在删除j个字符的情况下能取到多少种情况。由于第i个字符只有删除以及不能删除两种情况,可以得到dp[i][j] = dp[i – 1][j](第i个字符不删,前i-1个字符删除掉j个再加上当前字符能取到的个数) + dp[i – 1][ j – 1](第i个字符删了,前i-1个字符删除掉j-1个能取到的个数)~注意可能存在的重复情况,如liuchuo在dp[6][3]时删除下标为3、4、5的”uch”后得到字符串的与删除下标为4、5、6的”chu”后得到的字符串都为”liu”,所以需要记录当前(下标为i)字符上一次出现的位置last(存在vis数组中),并判断i与last的差是否大于等于目前的j,如果更多的话,就已经不可能受到影响了,故需要减去dp[last – 1][j – (i – last)]的数量。 最后将所有删减情况加起来,得到最终答案~
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
#include <bits/stdc++.h> using namespace std; string s; long long dp[1000001][4], vis[128], last; int main() { cin >> s; for (int i = 0; i <= s.size(); i++) dp[i][0] = 1; for (int i = 1; i <= s.size(); i++) { last = vis[s[i - 1]]; vis[s[i - 1]] = i; for (int j = 1; j <= 3; j++) { dp[i][j] = dp[i - 1][j] + dp[i - 1][j - 1]; if (last && j - (i - last) >= 0) dp[i][j] -= dp[last - 1][j - (i - last)]; } } cout << dp[s.size()][0] + dp[s.size()][1] + dp[s.size()][2] + dp[s.size()][3]; return 0; } |
❤ 点击这里 -> 订阅《PAT | 蓝桥 | LeetCode学习路径 & 刷题经验》by 柳婼