代码随想录算法训练营第五十二天 | 647.回文子串,516.最长回文子序列,动态规划总结

647. 回文子串

题目讲解:代码随想录
重点:

  1. 理解dp数组的含义及递推公式。

思路:

  1. dp数组的含义
// 子串[i,j]是否是回文子串, 如果是dp[i][j]为true, 否则为false
boolean[][] dp = new boolean[sArray.length][sArray.length];
  1. 递推公式
// s[i]与s[j]相等, 分三种情况
if (sArray[i] == sArray[j]) {
  // 第一种, 是同一个字符
  if (j == i) {
       dp[i][j] = true;
       result++;
   // 第二种, 两个字符相邻
   } else if (j - i == 1) {
   	   dp[i][j] = true;
       result++;
   // 第三种, 两个字符间隔一个或多个字符, 看内部子串是否为回文子串
   } else {
       if (dp[i + 1][j - 1]) {
           dp[i][j] = true;
           result++;
       }
   }
}
  1. dp数组的初始化
// 第一个字符和它本身肯定为回文子串
dp[0][0] = true;
  1. 遍历顺序
// 递推公式用到了dp[i + 1][j - 1], 在左下角, 所以先遍历列, 再遍历行
for (int j = 0; j < sArray.length; j++)
   for (int i = 0; i < sArray.length; i++)
  1. 模拟dp数组

public int countSubstrings(String s) {
    int result = 0;
    char[] sArray = s.toCharArray();
    // 子串[i,j]是否是回文子串, 如果是dp[i][j]为true, 否则为false
    boolean[][] dp = new boolean[sArray.length][sArray.length];
    // 第一个字符和它本身肯定为回文子串
    dp[0][0] = true;
    // 递推公式用到了dp[i + 1][j - 1], 在左下角, 所以先遍历列, 再遍历行
    for (int j = 0; j < sArray.length; j++) {
        for (int i = 0; i < sArray.length; i++) {
            if (i > j) break;
            // s[i]与s[j]相等, 分三种情况
            if (sArray[i] == sArray[j]) {
                // 第一种, 是同一个字符
                if (j == i) {
                    dp[i][j] = true;
                    result++;
                // 第二种, 两个字符相邻
                } else if (j - i == 1) {
                    dp[i][j] = true;
                    result++;
                // 第三种, 两个字符间隔一个或多个字符, 看内部子串是否为回文子串
                } else {
                    if (dp[i + 1][j - 1]) {
                        dp[i][j] = true;
                        result++;
                    }
                }
            }
        }
    }
    return result;
}

516. 最长回文子序列

题目讲解:代码随想录
重点:

  1. 理解dp数组的含义及递推公式。

思路:

  1. dp数组的含义
// 字符串s在[i,j]范围内最长的回文子序列的长度为dp[i][j]
int[][] dp = new int[sArray.length][sArray.length];
  1. 递推公式
// 当前字符相等, 内部最长回文加2
if (sArray[i] == sArray[j]) dp[i][j] = dp[i + 1][j - 1] + 2;
// 当前字符不相等, 取 不取i 和 不取j 的最大值
else dp[i][j] = Math.max(dp[i + 1][j], dp[i][j - 1]);
  1. dp数组的初始化
// 只有字符本身自己, 所以长度为1
for (int i = 0; i < sArray.length; i++) dp[i][i] = 1;
  1. 遍历顺序
// 从下往上, 从左往右遍历
for (int i = sArray.length - 1; i >= 0; i--)
   for (int j = i + 1; j < sArray.length; j++)
  1. 模拟dp数组

public int longestPalindromeSubseq(String s) {
    char[] sArray = s.toCharArray();
    // 字符串s在[i,j]范围内最长的回文子序列的长度为dp[i][j]
    int[][] dp = new int[sArray.length][sArray.length];
    // 只有字符本身自己, 所以长度为1
    for (int i = 0; i < sArray.length; i++) dp[i][i] = 1;
    // 从下往上, 从左往右遍历
    for (int i = sArray.length - 1; i >= 0; i--) {
        for (int j = i + 1; j < sArray.length; j++) {
            // 当前字符相等, 内部最长回文加2
            if (sArray[i] == sArray[j]) {
                dp[i][j] = dp[i + 1][j - 1] + 2;
            // 当前字符不相等, 取 不取i 和 不取j 的最大值
            } else {
                dp[i][j] = Math.max(dp[i + 1][j], dp[i][j - 1]);
            }
        }
    }
    return dp[0][sArray.length - 1];
}

动态规划总结

总结讲解:代码随想录

动规五部曲

确定dp数组(dp table)以及下标的含义
确定递推公式
dp数组如何初始化
确定遍历顺序
举例推导dp数组

动规结束语

在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值