返回

用 173 周赛 LeetCode 题目: 字符串 删除最低代价解决回文子序列问题

前端

前端工程师的 LeetCode 之旅:173 周赛

前言

LeetCode 是一个在线算法竞赛平台,提供各种编程语言的算法题目。通过解决这些题目,可以锻炼我们的编程能力和算法思维。173 周赛是 LeetCode 最近举办的一场比赛,其中有一道题目的解法非常巧妙,值得我们学习。

题目

给定一个字符串 s,它仅由字符 'a' 和 'b' 组成。每一次删除操作都可以从 s 中删除一个回文子序列。返回删除给定字符串所有字符(字符串为空)的最小删除次数。

子序列定义:

如果一个字符串可以通过删除原字符串某些字符而不改变原字符顺序得到,那么这个字符串就是原字符串的子序列。

示例

  • 输入:s = "ababa"

  • 输出:1

  • 解释:只需一次删除操作,就可以删除字符串 "ababa" 中的所有字符。

  • 输入:s = "abba"

  • 输出:2

  • 解释:需要两次删除操作,才能删除字符串 "abba" 中的所有字符。

  • 输入:s = "aaabb"

  • 输出:2

  • 解释:需要两次删除操作,才能删除字符串 "aaabb" 中的所有字符。

解题思路

这道题的关键在于找到一个合适的动态规划方程。我们定义状态 dp[i][j] 为从字符串 s[i] 到 s[j] 中删除所有字符的最小删除次数。根据题目的定义,我们可以得到如下动态规划方程:

dp[i][j] = min(dp[i][j-1], dp[i+1][j]) + 1

其中,dp[i][j-1] 表示从字符串 s[i] 到 s[j-1] 中删除所有字符的最小删除次数,dp[i+1][j] 表示从字符串 s[i+1] 到 s[j] 中删除所有字符的最小删除次数。

代码实现

def min_deletions(s):
  """
  删除字符串 s 中的所有字符(字符串为空)的最小删除次数。

  Args:
    s: 字符串 s,仅由字符 'a''b' 组成。

  Returns:
    最小删除次数。
  """

  n = len(s)
  dp = [[0] * n for _ in range(n)]

  for i in range(n-1, -1, -1):
    dp[i][i] = 1
    for j in range(i+1, n):
      if s[i] == s[j]:
        dp[i][j] = dp[i+1][j-1]
      else:
        dp[i][j] = min(dp[i][j-1], dp[i+1][j]) + 1

  return dp[0][n-1]

复杂度分析

  • 时间复杂度:O(n^2),其中 n 为字符串 s 的长度。
  • 空间复杂度:O(n^2)。

总结

这道题是一道非常典型的动态规划问题。通过定义状态和状态转移方程,我们可以很容易地求出最小删除次数。希望大家能够通过这道题学到一些动态规划的知识。