Skip to content

算法训练营 Day 56 | ● 647. 回文子串 ● 516.最长回文子序列 #53

Description

@KoEkko

647. 回文子串

布尔类型的dp[i][j]:表示区间范围[i,j] (注意是左闭右闭)的子串是否是回文子串,如果是dp[i][j]为true,否则为false。
在确定递推公式时,就要分析如下几种情况。

整体上是两种,就是s[i]与s[j]相等,s[i]与s[j]不相等这两种。

当s[i]与s[j]不相等,那没啥好说的了,dp[i][j]一定是false。

当s[i]与s[j]相等时,这就复杂一些了,有如下三种情况

情况一:下标i 与 j相同,同一个字符例如a,当然是回文子串
情况二:下标i 与 j相差为1,例如aa,也是回文子串
情况三:下标:i 与 j相差大于1的时候,例如cabac,此时s[i]与s[j]已经相同了,我们看i到j区间是不是回文子串就看aba是不是回文就可以了,那么aba的区间就是 i+1 与 j-1区间,这个区间是不是回文就看dp[i + 1][j - 1]是否为true。

if (s[i] == s[j]) {
    if (j - i <= 1) { // 情况一 和 情况二
        result++;
        dp[i][j] = true;
    } else if (dp[i + 1][j - 1]) { // 情况三
        result++;
        dp[i][j] = true;
    }
}

dp数组初始化为false

确定遍历顺序
首先从递推公式中可以看出,情况三是根据dp[i + 1][j - 1]是否为true,在对dp[i][j]进行赋值true的。
也就是需要感觉dp[i][j]的左下角dp[i + 1][j - 1]来推导,所以我们需要先对下面和左边的值进行计算。
如果这矩阵是从上到下,从左到右遍历,那么会用到没有计算过的dp[i + 1][j - 1],也就是根据不确定是不是回文的区间[i+1,j-1],来判断了[i,j]是不是回文,那结果一定是不对的。
也就是需要从下往上,从左往右去遍历

** 因为dp[i][j]的定义,所以j一定是大于等于i的,那么在填充dp[i][j]的时候一定是只填充右上半部分。 **

function countSubstrings(s: string): number {
  /**
   * dp[i][j] 表示 s[i] 到 s[j] 之间的字符串是否是回文子串
   */
  const dp: boolean[][] = new Array(s.length)
    .fill(0)
    .map((_) => new Array(s.length).fill(false));
  let result: number = 0;
  for (let i = s.length - 1; i >= 0; i--) {
    for (let j = i; j < s.length; j++) {
      if (s[i] === s[j]) {
        if (j - i <= 1) {
          dp[i][j] = true;
          result++;
        } else {
          if (dp[i + 1][j - 1]) {
            dp[i][j] = true;
            result++;
          }
        }
      }
    }
  }
  return result;
}

516.最长回文子序列

function longestPalindromeSubseq(s: string): number {
  /**
   * dp[i][j] 表示 s[i] 到 s[j]之间的字符串中有dp[i][j]个回文子序列
   */
  const dp: number[][] = new Array(s.length)
    .fill(0)
    .map((_) => new Array(s.length).fill(0));
  for (let i = 0; i < s.length; i++) dp[i][i] = 1;
  for (let i = s.length - 1; i >= 0; i--) {
    for (let j = i + 1; j < s.length; j++) {
      if (s[i] === s[j]) dp[i][j] = dp[i + 1][j - 1] + 2;
      else dp[i][j] = Math.max(dp[i][j - 1], dp[i + 1][j]);
    }
  }
  return dp[0][s.length - 1];
}

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions