动态规划--回文串问题

news2024/10/7 18:29:07

一)回文子串:

647. 回文子串 - 力扣(LeetCode)

思路1:暴力枚举:

for(int i=0;i<array.length;i++)

for(int j=i;j<array.length;j++)

我们的中心思路就是枚举出所有的子字符串,然后进行判断所有的子串是否是回文串

思路2:中心扩散:

我们从左向右遍历字符串中的每一个字符,遍历到某一个字符之后,我们向左向右各走一步,判断这个字符的左右两边是否相等,我们可以向左向右各走一步,如果两边不一样或者某一边走出了字符串的边界位置;

但是如果是偶数的情况,可以是选取两个字符从中间向两边进行扩展

思路3:动态规划

回文串问题是用动态规划解决可以进行判断能够将所有的子串是否是回文的信息,保存在dp表里面,dp[i][j]表示以i位置为起点,j位置为中点的子串,是否是回文串

3.1)如果array[i]!=array[j]那么从i位置到j位置的这段字符串,一定不是回文串

3.2)如果array[i]==array[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]

进行填表的时候只是会用到上三角的值,从下向上填表,从左向右进行填表

初始化:不用初始化

填表顺序:从下向上,从左向右,因为当进行填写当前行的时候要使用到下一行的值

返回值:返回的是dp表中true的个数

class Solution {
    public int countSubstrings(String s) {
        int count=0;
        char[] array=s.toCharArray();
        boolean[][] dp=new boolean[array.length][array.length];
        for(int i=array.length-1;i>=0;i--){
            for(int j=i;j<array.length;j++){
                if(array[i]==array[j]){
                    dp[i][j]=i+1==j||i==j?true:dp[i+1][j-1];
                }else{
                   dp[i][j]=false;
                }
                if(dp[i][j]==true) count++;
            }
        }
    return count;

    }
}

二)最长回文子串:

5. 最长回文子串 - 力扣(LeetCode)

class Solution {
    public String longestPalindrome(String s) {
        char[] array=s.toCharArray();
        int maxlen=-1;
        String maxString="";
        boolean[][] dp=new boolean[array.length][array.length];
        for(int i=array.length-1;i>=0;i--){
            for(int j=i;j<array.length;j++){
                if(array[i]==array[j]){
                    dp[i][j]=(j==i+1||i==j)?true:dp[i+1][j-1];
            if(j-i+1>=maxlen){
                    maxString=s.substring(i,j+1);
                    maxlen=j-i+1;
            }
                }else{
                    dp[i][j]=false;
                }
            }
        }
    return maxString;
    }
}

三)回文串分割:

1745. 分割回文串 IV - 力扣(LeetCode)

暴力枚举:将所有的三元组字符串给进行枚举一下,将所有的分割出来的三个字符串给进行枚举一下,只要枚举完成,只需要将三个字符串都进行判断一下是否是回文即可

我们将整个字符串分割成三部分:

class Solution {
    public boolean checkPartitioning(String s) {
//1.利用dp来进行检查一下所有的子串是否回文
        char[] array=s.toCharArray();
        boolean[][] dp=new boolean[array.length][array.length];
        for(int i=array.length-1;i>=0;i--){
            for(int j=i;j<array.length;j++){
                if(array[i]==array[j]){
                    dp[i][j]=i+1==j||i==j?true:dp[i+1][j-1];
                }else{
                   dp[i][j]=false;
                }
            }
        }
//2.枚举第二个字符串的所有的起始位置和终止位置
    for(int i=1;i<array.length;i++){//既然是枚举第二个字符串,那么前一个字符串必须得存在
        for(int j=i;j<array.length-1;j++){//至少要给最后一个字符串枚举
    if(dp[0][i-1]==true&&dp[i][j]==true&&dp[j+1][array.length-1]==true){
                return true;
            }
        }
    }
 return false;
    }
}

四)分割回文串:

132. 分割回文串 II - 力扣(LeetCode)

1)定义一个状态表示:

dp[i]表示以字符串i为结尾最长的子串的最少分割次数

2)根据状态标识推导状态转移方程

1)快速确定某一个字符串的子串是否是回文串

2)可以创建一个二维dp表,将所有的子串是否是回文的信息,保存到hash表里面

j==0的时候,0-i位置的字符传是否是回文子串已经考虑过了

j==i的时候,起始位置就是最后一个字符

 如果判断f[0][i]的逻辑写到循环里面

    public int minCut(String s) {
        char[] array=s.toCharArray();
        boolean[][] f=new boolean[array.length][array.length];
        int[] g=new int[array.length];
        for(int i=array.length-1;i>=0;i--){
            for(int j=i;j<array.length;j++){
                if(array[i]==array[j]){
                    f[i][j]=i==j||i+1==j?true:f[i+1][j-1];
                }else{
                    f[i][j]=false;
                }
            }
        }
    for(int i=0;i<array.length;i++) 
    {
        g[i]=Integer.MAX_VALUE;
    }
   // System.out.println(Arrays.deepToString(f));
    for(int i=0;i<array.length;i++){
        for(int j=1;j<=i;j++){
            //1.首先判断0-i位置是否是回文子串
             if(f[0][i]==true) g[i]=0;
             else if(f[j][i]==true){
                g[i]=Math.min(g[i],g[j-1]+1);
        }
     }
    }
 return g[array.length-1];
    
}

 上面这么写会导致进行计算f[0][0]的时候计算错误

 五)最长回文子序列

516. 最长回文子序列 - 力扣(LeetCode)

一)定义一个状态表示:

1)以i位置元素为结尾的所有子序列中最长的回文子序列的长度,如果这样定义状态标识,根本推不出状态转移方程,如果以i位置为结尾,势必就会使用到i-1,i-2等等位置的dp值来更新当前i位置的dp值,假设我们就举一个例子,dp[i-3]表示以i-3位置为结尾的最长回文子序列的长度,但是我只是知道长度,我连i位置的元素是否可以和i-3位置的元素是否能够构成回文子序列都不知道,请问我该如何更新dp[i]的值呢?是永远无法更新出最长回文子序列的长度,首先得知道是否能够成回文子序列?根本判断不出来,根本不能由前面的状态来推导出dp[i]的值,从下图所示可以看出,从[i,j]这段区间内最长回文子序列的长度可以推导出[i+1,j+1]这段区间内最长回文子序列的长度

 二)根据状态标识推到状态转移方程

根据最后一个位置推导问题(i<=j)

三)初始化,填表顺序,返回值 

填表顺序当进行填写dp表的时候,进行填写到dp[i][j]的时候,需要dp[i+1][j]的值,需要使用到下一行的值和dp[i][j-1]需要用到左边的值,所以填表顺序就是从下向上,从左向右

返回值:返回dp[0][array.length-1]里面的值

class Solution {
    public int longestPalindromeSubseq(String s) {
      char[] array=s.toCharArray();
//1.dp[i][j]表示以i位置为开头,j位置元素为结尾最长回文子序列的长度
      int[][] dp=new int[array.length][array.length];
//2.进行填写dp表,从下向上进行填表
      for(int i=array.length-1;i>=0;i--){
          for(int j=i;j<array.length;j++){
             if(array[i]==array[j]){
                 if(i==j) dp[i][j]=1;
                 else if(i+1==j) dp[i][j]=2;
                 else dp[i][j]=dp[i+1][j-1]+2;
             }else{
                 dp[i][j]=Math.max(dp[i+1][j],dp[i][j-1]);
             }
          }
      }
    return dp[0][array.length-1];
    }
}

六)让字符串成为回文串的最少插入次数

让字符串成为回文串的最少插入次数

做回文串的题的时候,状态表示都是定义一段区间内的值

一)定义一个状态表示

dp[i][j]表示s字符串内[i,j]这段区间内的字符串使他成为回文串的最小插入次数

二)根据状态表示推导状态转移方程

我们还是根据最近的一步划分问题

 

class Solution {
    public int minInsertions(String s) {
    char[] array=s.toCharArray();
    int[][] dp=new int[array.length][array.length];
//1.dp[i][j]表示以i位置为起点,j位置为终点得是这段区间成为回文串得最小插入次数
 for(int i=array.length-1;i>=0;i--){
     for(int j=i;j<array.length;j++){
         if(array[i]==array[j]){
             if(i==j) dp[i][j]=0;
             else if(i+1==j) dp[i][j]=0;
             else dp[i][j]=dp[i+1][j-1]; 
         }else{
             dp[i][j]=Math.min(dp[i+1][j]+1,dp[i][j-1]+1);
         }
     }
 }
   return dp[0][array.length-1];
    }
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/783692.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

​MySQL高阶语句(三)

目录 1、内连接 2、左连接 3、右连接&#xff1a; 二、存储过程⭐⭐⭐ 4. 调用存储过程 5.查看存储过程 5.1 查看存储过程 5.2查看指定存储过程信息 三. 存储过程的参数 3.1存储过程的参数 3.2修改存储过程 四.删除存储过程 MySQL 的连接查询&#xff0c;通常都是将来…

ElasticSearch学习--RestClient及案例

目录 RestClient查询文档 快速入门 总结 全文检索&#xff08;match&#xff09;查询 精确查询 复合查询 查询总结 排序&#xff0c;分页 高亮 RestClient查询文档 快速入门 总结 全文检索&#xff08;match&#xff09;查询 多种查询的差异都在做类型和条件上&#x…

JS 自定义的悬浮窗被浏览器遮挡问题解决方案

遮挡问题解决思路&#xff0c;首先拿到外层的DOM元素div的宽高&#xff0c;然后根据鼠标悬浮事件的元素e e.clientX表距离页面窗口宽的位置 e.clientY代表距离页面窗口高的位置 然后设置这个悬浮窗为200px 那个这个div的宽高 dom.getElementById(xxxx).cliengHeight dom.g…

FutureTask

Future接口 Future接口&#xff08;FutureTask实现类&#xff09;定义了操作异步任务执行一些方法&#xff0c;如获取异步任务执行的结果、取消任务的执行、判断任务是否取消、判断任务执行是否完成等。它提供了一种并行异步计算的功能。比如主线程让子线程去执行任务&#xff…

C语言两种方法求证大小端存储

目录 什么是大小端存储&#xff1f; 字节序的概念&#xff1a; 小端字节序存储&#xff1a; 大端字节序存储&#xff1a; 什么是低位字节、高位字节&#xff1f; 记忆技巧&#xff1a; C语言求证大小端存储 法一&#xff1a; 法二&#xff1a; 总结&#xff1a; 什么是…

CAXA中.exb或者.dwg文件保存为PDF

通常CAXAZ中的文件为.exb或者.dwg格式&#xff0c;我们想打印或者保存为PDF文件格式&#xff0c;那么就用一下的方法&#xff1a; CAXA文件如图所示&#xff1a; 框选出你要打印的图纸&#xff01;&#xff01;&#xff01;&#xff01; 我们选择"菜单"->"…

用户订单信息案例

需求: 用户输入商品价格和商品数量&#xff0c;以及收货地址&#xff0c;可以自动打印订单信息 分析: ① 需要输入3个数据&#xff0c;所以需要3个变量来存储price num address ② 需要计算总的价格total ③ 页面打印生成表格, 里面填充数据即可 ④ 记得最好使用模板字符串 【…

java.io.InputStreamReader的read()函数返回值是字符对应的Unicode码点

java.io.InputStreamReader的read()函数定义&#xff1a; https://docs.oracle.com/en/java/javase/19/docs/api/java.base/java/io/InputStreamReader.html#read() 这个返回的值其实就是解码后的字符对应的Unicode码点&#xff08;Unicode code point&#xff09;。 举例 例如…

MySQL表的管理

目录 1.mysql中&#xff0c;数据存储过程分为四步 2.数据库命名规则 3.创建数据库 4.管理数据库的方法 5.修改数据库&#xff08;一般不改&#xff0c;最多改字符集&#xff09; 6.删除数据库 7.如何创建数据表 8.修改表 9.重命名表 10.删除表&#xff08;注意⚠️无…

Java日志slf4j+logback

一、maven依赖 在pom文件增加slf4jlogback依赖 <!-- 版本配置 --> <properties><slf4j.version>1.7.21</slf4j.version><logback.version>1.1.7</logback.version> </properties><dependencies><!-- slf4j依赖包 -->&…

JVM源码剖析之达到什么条件进行JIT优化

版本信息&#xff1a; jdk版本&#xff1a;jdk8u40 思想至上 技术经过数百年的迭代&#xff0c;如今虚拟机中都存在JIT模块&#xff0c;JVM中Hotspot&#xff0c;Android虚拟机中dalvik、Art等等。并且存在一个共性&#xff0c;全部都是解释器和JIT共存。当然&#xff0c;如今…

六、模型融合

目录 1 构建模型多样性1.1 特征多样性1.2 样本多样性1.3 模型多样性 2. 训练过程融合2.1 Bagging2.2 Boosting 3. 训练结果融合3.1 加权法3.2 Stacking 融合3.3 Blending 融合 4. 实战案例 本章主要分为构建多样性、训练过程融合和训练结果融合三部分。模型融合常常是竞赛取得胜…

神州通用数据库Linux安装

神舟通用1.安装包下载地址 神舟通用 操作系统、数据库 1、官方下载链接 2、windows客户端下载链接 3、官方安装手册 4、安装前准备 3.1、创建安装用户 3.2、以root 用户修改神通数据库安装包的所有者为shentong 用户 3.3、以root 用户创建神通数据库主目录并修改所有者为shent…

欧姆龙cx系列plc串门通讯设置串口转以太网通讯处理器

捷米特JM-ETH-CX 串口转以太网通讯处理器是为满足日益增多的工厂设备信息化需求&#xff08;设备网络监控和生产管理&#xff09;而设计&#xff0c;用于欧姆龙 CPM、CQM、C200、C1000、C2000 等多个系列 PLC 的以太网数据采集&#xff0c; 非常方便构建生产管理系统。 捷米特J…

Linux内核--五大子系统

Linux内核有五大核心子系统&#xff0c;分别是进程调度系统、虚拟文件系统(VFS)、内存管理单元(MMU)、网络单元、进程间通信(IPC)。 在Linux内核中的主要组件中&#xff0c;五个核心子系统是最为重要的组成部分&#xff0c;它与系统调用接口&#xff08;System Call Interface&…

docker-compose安装redis一主二从三哨兵集群

准备 docker安装参考&#xff1a; CentOS 安装 docker详解_centos安装docker_慕菲烟云的博客-CSDN博客 docker-compose安装参考&#xff1a;docker之docker-compose_docker compose no-cache_慕菲烟云的博客-CSDN博客 准备一台Linux服务器&#xff08;IP &#xff1a;192.1…

连连看小游戏(html+css+js)

花费了2个小时的摸鱼时间&#xff0c;我成功地编写了一个精彩的连连看小游戏&#xff0c;让我感到非常开心和满足。这款游戏玩起来相当出色&#xff0c;现在我很高兴地与大家分享。 在这个连连看小游戏的设计过程中&#xff0c;我注重细节和用户体验。通过精心安排的图形和布局…

Linux学习笔记--如何在ubuntu中启用root用户和安装软件的方法(解决安装依赖)

一、ubuntu启用root用户 打开Terminal(终端)&#xff0c;右键点击桌面&#xff0c;选择终端&#xff0c;弹出终端窗口。&#xff08;使用快捷键ctrlaltt&#xff0c;也可以调出Terminal&#xff09;。 指令su&#xff0c;该指令可切换用户或者切换到超级管理员root。 su 在终端…

操作系统_进程与线程(一)

目录 1. 进程与线程 1.1 进程的概念 1.2 进程的特征 1.3 进程的状态与转换 1.4 进程的组织 1.4.1 进程控制块PCB 1.4.2 程序段 1.4.3 数据段 1.5 进程控制 1.5.1 进程的创建 1.5.2 进程的终止 1.5.3 进程的阻塞和唤醒 1.6 进程的通信 1.6.1 共享存储 1.6.2 消息…