7月29日-8月4日 动态规划(困难部分) 算法总结

109 阅读3分钟

动态规划(Dynamic Programming,简称DP)是一种在算法设计中非常有用的技术,它通过将复杂问题分解为更小的子问题,并将子问题的解存储起来,避免了重复计算,从而提高了算法的效率。上周的题目主要是动态规划的基础,这周刷的题包括最长回文子串、最长上升子序列、兑换零钱和编辑距离等较为困难的部分。

1. 最长回文子串

回文是正读和反读都相同的字符串。最长回文子串问题是找出给定字符串中最长的回文子串。

思路

  • 我们可以使用动态规划来解决这个问题。设dp[i][j]表示从索引ij的子串是否是回文。
  • 如果s[i] == s[j],那么dp[i][j]的值取决于dp[i + 1][j - 1]
  • 如果s[i] != s[j],则dp[i][j]False

算法步骤

  1. 初始化dp数组,所有值为False
  2. 将所有长度为1的子串设置为回文(dp[i][i] = True)。
  3. 考虑长度为2的子串,如果两个字符相同,则设置为回文。
  4. 对于更长的子串,使用递推关系更新dp数组。
  5. 遍历dp数组,找到最大的True区域,即为最长回文子串。

2. 最长上升子序列

最长上升子序列问题是找出给定整数序列中最长的严格递增子序列。

思路

  • 动态规划数组dp[i]表示以第i个元素结尾的最长上升子序列的长度。
  • 状态转移方程为:dp[i] = max(dp[i], dp[j] + 1),其中j < iarr[j] < arr[i]

算法步骤

  1. 初始化dp数组,所有值为1。
  2. 遍历数组,对于每个元素,检查其之前的所有元素,更新dp数组。
  3. 最大值即为最长上升子序列的长度。

3. 兑换零钱

兑换零钱问题是给定一定数量的硬币和总金额,找出最少需要多少个硬币。

思路

  • 使用动态规划数组dp[i]表示组成金额i所需的最少硬币数量。
  • 状态转移方程为:dp[i] = min(dp[i - coin] + 1, dp[i])

算法步骤

  1. 初始化dp数组,dp[0] = 0,其他值为无穷大。
  2. 遍历每个硬币,更新dp数组。
  3. dp[amount]即为所需的最少硬币数量。

4. 编辑距离

编辑距离问题是计算两个字符串之间,通过插入、删除或替换字符,将一个字符串转换为另一个字符串所需的最少操作数。

思路

  • 使用动态规划数组dp[i][j]表示将第一个字符串的前i个字符转换为第二个字符串的前j个字符所需的最少操作数。
  • 状态转移方程取决于两个字符串的当前字符是否相同。

算法步骤

  1. 初始化dp数组,dp[0][j] = jdp[i][0] = i
  2. 遍历两个字符串,根据当前字符是否相同更新dp数组。
  3. dp[m][n]即为所需的最少操作数。

结语

通过本周对动态规划的深入学习,进一步掌握了解决上述问题的方法,还学会了如何将动态规划应用于其他问题。与其说难度提高,不如说是更加需要将具象的题目抽象化的能力,得出状态转移方程,进一步将方程翻译为代码,问题便可迎刃而解。