「LeetCode」1312-让字符串成为回文串的最少插入次数

308 阅读1分钟

一起养成写作习惯!这是我参与「掘金日新计划 · 4 月更文挑战」的第20天,点击查看活动详情

一.题目:

1312. 让字符串成为回文串的最少插入次数 给你一个字符串 s ,每一次操作你都可以在字符串的任意位置插入任意字符。

请你返回让 s 成为回文串的 最少操作次数 。

「回文串」是正读和反读都相同的字符串。

示例 1:

输入: s = "zzazz"
输出: 0
解释: 字符串 "zzazz" 已经是回文串了,所以不需要做任何插入操作。

示例 2:

输入: s = "mbadm"
输出: 2
解释: 字符串可变为 "mbdadbm" 或者 "mdbabdm"

示例 3:

输入: s = "leetcode"
输出: 5
解释: 插入 5 个字符后字符串变为 "leetcodocteel" 。

提示:

  • 1 <= s.length <= 500
  • s 中所有字符都是小写字母。

二、思路分析:

今天继续来巩固动态规划类型的题目,这道题目难度显示为困难,但是如果你熟悉动态规划,就会发现这道题的思路特别简单。题目的思路如下:

  • 定义dp数组:我们定义dp[i][j]为从ij位置成为回文串的最小操作数,所以最终求得结果就是从0n-1的最小操作数dp[0][n-1]
  • 进行初始化:我们知道每一个字符就是一个回文串,所以每个字符的最小操作数是0,因为它不需要进行操作。
  • 明确状态转移方程:我们根据题目得知,如果发现ij不相同后,我们只能进行插入操作,即可能是i+1的位置进行插入操作,也可能是j-1的位置,所以情况全部写出来然后取最小值即可:dp[i][j] = Math.min(dp[i + 1][j], dp[i][j - 1]) + 1;如果相同则不需要进行插入操作。
  • 根据状态转移方程明确遍历顺序:由状态转移方程得知遍历顺序是从下到上从左到右的,所以可以确定遍历位置。

三、代码:

/**
 * @param {string} s
 * @return {number}
 */
var minInsertions = function (s) {
    let n = s.length
    //dp定义:dp[i][j]为从i到j位置成为回文串的最小操作数
    let dp = Array.from(new Array(n), () => new Array(n).fill(0) )
    //初始化:每个字符都是回文串,所以dp[i][j] == 0
    for (let i = 0; i < n; i++) {
        dp[i][i] = 0
    }
    for (let i = n - 2; i >= 0; i--) {
        for (let j = i+1; j < n; j++) {
            //状态转移方程:s[i]与s[j]相等,dp[i][j] = dp[i]
            if (s[i] == s[j]) {
                dp[i][j] = dp[i + 1][j - 1]
            } else {
                //需要进行插入操作
                dp[i][j] = Math.min(dp[i + 1][j], dp[i][j - 1]) + 1
            }
        }
    }
    return dp[0][n-1]
};

四、总结:

这样的最值问题一般都是采用动态规划进行求解问题的,所以一定要掌握动态规划的核心思想:即数组的定义、状态转移方程等,如果不能够确定遍历顺序,需要通过画图进行理解。