字符串构造 |豆包MarsCode AI刷题

38 阅读3分钟

小S有一个长度为n的字符串 s,她可以进行一种特殊的操作——将字符串中的部分折叠为回文子串。每次操作时,可以选择其中一个回文子串的左侧或右侧的部分折叠成一个子串,折叠的次数不限(可以折叠0次)。小S想知道,通过这种操作可以生成多少种不同的字符串。 例如,"aba"向左可以折叠成"ab"。"abba"向右可以折叠成"ba"。

  1. 定义常量及判断回文函数

    • 首先定义常量 MOD,其值为 10 ** 9 + 7,用于后续取模操作,确保结果在规定范围内。然后定义一个函数 is_palindrome,用于判断一个字符串是否为回文串,通过比较字符串本身和其逆序字符串是否相等(s == s[::-1])来返回判断结果。
  2. 初始化动态规划数组

    • 创建一个长度为 n 的列表 dp,初始值都设为 1。这里的 dp[i] 表示到字符串 s 的第 i 个字符为止,通过给定操作能生成的不同字符串的数量(初始时每个字符位置自身算一种情况)。
  3. 动态规划递推计算不同字符串数量

    • 通过两层嵌套的循环来进行动态规划的递推计算。外层循环控制当前考虑的字符位置 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 取模,以保证结果始终在规定范围内。
  4. 返回最终结果

    • 当两层循环结束后,dp 列表的最后一个元素 dp[-1] 存储的就是整个字符串 s 通过给定操作能生成的不同字符串的数量对 10 ** 9 + 7 取模后的结果,将其返回即可。

时间复杂度方面,外层循环遍历字符串长度的时间复杂度是 ,内层循环对于每个位置又遍历前面的位置,时间复杂度也是 ,在每次内层循环中判断子串是否为回文串的操作时间复杂度最坏情况下为 O(n)(取决于子串长度),综合起来整体时间复杂度大致为O(n)`(取决于子串长度),综合起来整体时间复杂度大致为 O(n^3),在处理常规长度的字符串时能够正确地计算出相应的结果并进行取模输出。