【算法篇】逐步理解动态规划模型6(回文串问题)

目录

回文串问题

1.回文子串

2.最长回文子串

3.分割回文串4


本文旨在通过对力扣上三道题进行讲解来让大家对使用动态规划解决回文串有一定思路,培养大家对状态定义,以及状态方程书写的思维。

顺序:

题目链接-》算法思路-》代码呈现

回文串问题

动态规划类题目解题步骤:

  1. 依据题目进行状态表示(dp[i]的含义)
  2. 写出状态转移方程(类似于dp[i]=dp[i-1]+dp[i-2])
  3. 为防止填表时数组越界,对dp表进行初始化(dp[0]=dp[1]=1)
  4. 搞清楚填表顺序(从前往后或者从后往前)
  5. 利用dp表返回问题答案

1.回文子串

题目链接:

https://leetcode.cn/problems/palindromic-substrings/

算法思路:
我们可以先「预处理」⼀下,将所有⼦串「是否回⽂」的信息统计在 dp 表⾥⾯,然后直接在表⾥⾯统计 true 的个数即可。

  1. 状态表⽰:
    为了能表⽰出来所有的⼦串,我们可以创建⼀个 n * n 的⼆维 dp 表,只⽤到「上三⻆部分」 即可。
    其中, dp[i][j] 表⽰: s 字符串 [i, j] 的⼦串,是否是回⽂串。

  2. 状态转移⽅程:
    对于回⽂串,我们⼀般分析⼀个「区间两头」的元素:

  3. 当 s[i] != s[j] 的时候:不可能是回⽂串, dp[i][j] = 0 ;

  4. 当 s[i] == s[j] 的时候:根据⻓度分三种情况讨论:

  • ⻓度为 1 ,也就是 i == j :此时⼀定是回⽂串, dp[i][j] = true ;
  • ⻓度为 2 ,也就是 i + 1 == j :此时也⼀定是回⽂串, dp[i][j] = true ;
  • ⻓度⼤于 2 ,此时要去看看 [i + 1, j - 1] 区间的⼦串是否回⽂: dp[i][j] = dp[i + 1][j - 1] 。

综上,状态转移⽅程分情况谈论即可。
3. 初始化:
因为我们的状态转移⽅程分析的很细致,因此⽆需初始化。
4. 填表顺序:
根据「状态转移⽅程」,我们需要「从下往上」填写每⼀⾏,每⼀⾏的顺序⽆所谓。
5. 返回值:
根据「状态表⽰和题⽬要求」,我们需要返回 dp 表中 true 的个数。

代码呈现:

java 复制代码
class Solution {
    public int countSubstrings(String s) {
     char[] arr=s.toCharArray();
     int n=arr.length;
     boolean[][] dp=new boolean[n][n];
     for(int j=0;j<n;j++){
        for(int i=j;i>=0;i--){
          if(arr[i]==arr[j]){
            if(i==j){
                dp[i][j]=true;
            }else if(i+1==j){
                dp[i][j]=true;
            }else{
                dp[i][j]=dp[i+1][j-1];
            }
          }else{
            dp[i][j]=false;
          }
        }
     }
     int re=0;
     for(int i=0;i<n;i++){
        for(int j=0;j<n;j++){
            if(dp[i][j]==true){
                re++;
            }
        }
     }
     return re;
    }
}

2.最长回文子串

题目链接:

https://leetcode.cn/problems/longest-palindromic-substring/description/

算法思路:

  1. 我们可以先⽤ dp 表统计出「所有⼦串是否回⽂」的信息
  2. 然后根据 dp 表⽰ true 的位置,得到回⽂串的「起始位置」和「⻓度」。

那么我们就可以在表中找出最⻓回⽂串。
关于「预处理所有⼦串是否回⽂」,已经在上⼀道题⽬⾥⾯讲过

代码呈现:

java 复制代码
class Solution {
    public String longestPalindrome(String s) {
      char[] arr=s.toCharArray();
      int n=arr.length;
      int[][] dp=new int[n][n];
      for(int j=0;j<n;j++){
        for(int i=j;i>=0;i--){
            if(arr[i]==arr[j]){
                if(i==j){
                    dp[i][j]=1;
                }else if(i+1==j){
                    dp[i][j]=2;
                }else{
                    if(dp[i+1][j-1]==0){
                        dp[i][j]=0;
                    }else{
                    dp[i][j]=dp[i+1][j-1]+2;
                    }
                }
            }else{
                dp[i][j]=0;
            }
        }
      }
      int max=0;
      String re="";
      for(int i=0;i<n;i++){
        for(int j=0;j<n;j++){
          if(max<dp[i][j]){
            max=dp[i][j];
            re=s.substring(i,j+1);
          }
        }
      }
      return re;
    }
}

3.分割回文串4

题目链接:

https://leetcode.cn/problems/palindrome-partitioning-iv/description/

算法思路:
题⽬要求⼀个字符串被分成「三个⾮空回⽂⼦串」,乍⼀看,要表⽰的状态很多,有些⽆从下⼿。
其实,我们可以把它拆成「两个⼩问题」:

  1. 动态规划求解字符串中的⼀段⾮空⼦串是否是回⽂串;
  2. 枚举三个⼦串除字符串端点外的起⽌点,查询这三段⾮空⼦串是否是回⽂串。

那么这道困难题就免秒变为简单题啦,变成了⼀道枚举题。
关于预处理所有⼦串是否回⽂,已经在上⼀道题⽬⾥⾯讲过。

代码呈现:

java 复制代码
class Solution {
    public boolean checkPartitioning(String s) {
       char[] arr=s.toCharArray();
       int n=arr.length;
       boolean[][] dp=new boolean[n][n];
       for(int j=0;j<n;j++){
        for(int i=j;i>=0;i--){
          if(arr[i]==arr[j]){
            if(i==j){
                dp[i][j]=true;
            }else if(i+1==j){
                dp[i][j]=true;
            }else{
                dp[i][j]=dp[i+1][j-1];
            }
          }else{
            dp[i][j]=false;
          }
        }
       }
       for(int i=1;i<n-1;i++){
        for(int j=i;j<n-1;j++){
            if(dp[0][i-1]&&dp[i][j]&&dp[j+1][n-1]){
                return true;
            }
        }
       }
       return false;
    }
}
相关推荐
这就是佬们吗5 分钟前
初识 docker [上]
java·开发语言·笔记·docker·容器
阿华的代码王国10 分钟前
【Android】卡片式布局 && 滚动容器ScrollView
android·xml·java·前端·后端·卡片布局·滚动容器
MediaTea15 分钟前
Python 库手册:doctest 文档测试模块
开发语言·python·log4j
苦学编程的谢21 分钟前
Mybatis_4
java·spring boot·tomcat·mybatis·mybatis_plus
她说..31 分钟前
MybatisPlus-快速入门
java·spring boot·spring cloud·微服务·mybatis·mybatisplus
哈密瓜刨冰37 分钟前
HTTP 协议的基本格式和 fiddler 的用法
java
hweiyu0038 分钟前
R语言简介(附电子书资料)
开发语言·r语言
hweiyu0040 分钟前
R语言常用扩展包
开发语言·r语言
砖头拍死你1 小时前
51单片机如何使用printf打印unsigned long的那些事
java·前端·51单片机
明明如月学长1 小时前
什么你不知道 Cherry Studio 有快捷助手?
算法