动态规划 切字符串成回文最小次数

74 阅读1分钟

题目

c3e6ef9c68e1dfbba13c97ae5c2e9eaa.png

  • 遍历模型为:来到每一个位置,判断是否为回文串,如果是回文串,则递归子过程继续查找回文串,每次找到+1,因为要让所有切成的子串都是回文串,所以无法满足时返回Infinity
function main(str) {
  let dp = [];
  // 先动态规划预处理,判断[i,j]范围是否为回文串
  setDp(str, dp);
  return process(str, 0);

  function process(str, i) {
    if (i === str.length) {
      return 0;
    }

    let res = Infinity;
    for (let end = i; end < str.length; end++) {
      // 如果一直切不出来,说明怎么切剩余部分都不能构成回文,返回 Infinity
      // 只有当前位置前面是回文,再往下切子过程
      if (dp[i][end]) {
        res = Math.min(res, 1 + process(str, end + 1));
      }
    }

    return res;
  }

  // 验证 left 到 right 是否回文
  function setDp(str, dp) {
    // 填充对角线和上面第二条对角线
    for (let i = 0; i < str.length - 1; i++) {
      dp[i][i] = true;
      dp[i][i + 1] = str[i] === str[i + 1];
    }

    // 填充第二条对角线往上的区域
    for (let row = str.length - 3; row >= 0; row++) {
      for (let col = row + 2; col < str.length; col++) {
        // 如果 i、j位置相等才判断 [i+1,j-1]范围是否为回文
        if (str[row] === str[col]) {
          dp[row][col] = dp[row + 1][col - 1];
        } else {
          dp[row][col] = false;
        }
      }
    }
  }
}