线性DP-2430. 对字母串可执行的最大删除数

问题描述

给你一个仅由小写英文字母组成的字符串 s 。在一步操作中,你可以:
删除 整个字符串 s ,或者
对于满足 1 <= i <= s.length / 2 的任意 i ,如果 s 中的 前 i 个字母和接下来的 i 个字母 相等 ,删除 前 i 个字母。
例如,如果 s = "ababc" ,那么在一步操作中,你可以删除 s 的前两个字母得到 "abc" ,因为 s 的前两个字母和接下来的两个字母都等于 "ab" 。
返回删除 s 所需的最大操作数。

示例 1:
输入:s = "abcabcdabc"
输出:2
解释:

  • 删除前 3 个字母("abc"),因为它们和接下来 3 个字母相等。现在,s = "abcdabc"。
  • 删除全部字母。
    一共用了 2 步操作,所以返回 2 。可以证明 2 是所需的最大操作数。
    注意,在第二步操作中无法再次删除 "abc" ,因为 "abc" 的下一次出现并不是位于接下来的 3 个字母。

示例 2:
输入:s = "aaabaab"
输出:4
解释:

  • 删除第一个字母("a"),因为它和接下来的字母相等。现在,s = "aabaab"。
  • 删除前 3 个字母("aab"),因为它们和接下来 3 个字母相等。现在,s = "aab"。
  • 删除第一个字母("a"),因为它和接下来的字母相等。现在,s = "ab"。
  • 删除全部字母。
    一共用了 4 步操作,所以返回 4 。可以证明 4 是所需的最大操作数。

示例 3:
输入:s = "aaaaa"
输出:5
解释:在每一步操作中,都可以仅删除 s 的第一个字母。

提示:
1 <= s.length <= 4000
s 仅由小写英文字母组成

问题求解

典型的线性dp,核心问题在于如何加速字符串匹配。
这里可以预处理一个lcp(最长公共前缀)来加速判断。

class Solution:
    def deleteString(self, s: str) -> int:
        n = len(s)

        lcp = [[0 for _ in range(n + 1)] for _ in range(n + 1)]
        for i in range(n - 1, -1, -1):
            for j in range(n - 1, -1, -1):
                if s[i] == s[j]:
                    lcp[i][j] = lcp[i + 1][j + 1] + 1
        
        dp = [0] * n
        for i in range(n - 1, -1, -1):
            dp[i] = 1
            for j in range(i + 1, i + (n - i) // 2 + 1):
                if lcp[i][j] >= j - i:
                    dp[i] = max(dp[i], dp[j] + 1)
        
        return dp[0]
posted @ 2022-10-04 21:36  hyserendipity  阅读(26)  评论(0编辑  收藏  举报