小S有一个长度为n的字符串 s,她可以进行一种特殊的操作——将字符串中的部分折叠为回文子串。每次操作时,可以选择其中一个回文子串的左侧或右侧的部分折叠成一个子串,折叠的次数不限(可以折叠0次)。小S想知道,通过这种操作可以生成多少种不同的字符串。 例如,"aba"向左可以折叠成"ab"。"abba"向右可以折叠成"ba"。
-
定义常量及判断回文函数:
- 首先定义常量
MOD,其值为10 ** 9 + 7,用于后续取模操作,确保结果在规定范围内。然后定义一个函数is_palindrome,用于判断一个字符串是否为回文串,通过比较字符串本身和其逆序字符串是否相等(s == s[::-1])来返回判断结果。
- 首先定义常量
-
初始化动态规划数组:
- 创建一个长度为
n的列表dp,初始值都设为 1。这里的dp[i]表示到字符串s的第i个字符为止,通过给定操作能生成的不同字符串的数量(初始时每个字符位置自身算一种情况)。
- 创建一个长度为
-
动态规划递推计算不同字符串数量:
-
通过两层嵌套的循环来进行动态规划的递推计算。外层循环控制当前考虑的字符位置
i,范围是从 0 到n - 1,表示遍历整个字符串s的每个位置。 -
内层循环控制前面的字符位置
j,范围是从 0 到i - 1,对于每个i和j的组合,取出从位置j到位置i(包含i)的子串sub_s(通过s[j:i + 1]切片操作获取)。 -
接着使用
is_palindrome函数判断这个子串sub_s是否是回文串,如果是回文串,进行以下计算来更新dp[i]的值:- 计算子串
sub_s左侧部分能生成的不同字符串数量left,如果j等于 0(即子串从字符串开头开始),则left设为 1,因为此时左侧没有其他字符了;如果j大于 0,则left取值为dp[j - 1],表示基于前面j - 1个字符位置能生成的不同字符串数量(因为左侧部分的情况可以参考前面已经计算好的结果)。 - 子串
sub_s右侧部分折叠后能生成的不同字符串数量right设为 1,这里简化考虑为只有一种折叠情况(可以折叠 0 次也算一种情况)。 - 然后根据乘法原理,将
left和right相乘,再加上原来的dp[i](表示之前已经累计的数量),得到新的dp[i]的值(dp[i] += left * right),并且每次更新dp[i]后都要对MOD取模,以保证结果始终在规定范围内。
- 计算子串
-
-
返回最终结果:
-
当两层循环结束后,
dp列表的最后一个元素dp[-1]存储的就是整个字符串s通过给定操作能生成的不同字符串的数量对10 ** 9 + 7取模后的结果,将其返回即可。
-
时间复杂度方面,外层循环遍历字符串长度的时间复杂度是 ,内层循环对于每个位置又遍历前面的位置,时间复杂度也是 ,在每次内层循环中判断子串是否为回文串的操作时间复杂度最坏情况下为 O(n^3),在处理常规长度的字符串时能够正确地计算出相应的结果并进行取模输出。