【面试算法——动态规划 19】最长回文子序列 (hard)让字符串成为回文串的最少插入次数

news2024/12/25 12:57:35

516. 最长回文子序列

链接: 516. 最长回文子序列

给你一个字符串 s ,找出其中最长的回文子序列,并返回该序列的长度。

子序列定义为:不改变剩余字符顺序的情况下,删除某些字符或者不删除任何字符形成的一个序列。

示例 1:

输入:s = “bbbab”
输出:4
解释:一个可能的最长回文子序列为 “bbbb” 。
示例 2:

输入:s = “cbbd”
输出:2
解释:一个可能的最长回文子序列为 “bb” 。

1.状态表示*
. 状态表⽰:
关于「单个字符串」问题中的「回⽂⼦序列」,或者「回⽂⼦串」,我们的状态表⽰研究的对象⼀般都是选取原字符串中的⼀段区域 [i, j] 内部的情况。这⾥我们继续选取字符串中的⼀段区域来研究:
dp[i][j] 表⽰:s字符串 [i, j] 区间内的所有的⼦序列中,最⻓的回⽂⼦序列的⻓度

2.状态转移方程
i. 当⾸尾两个元素「相同」的时候,也就是 s[i] == s[j] :那么 [i, j] 区间上的最
⻓回⽂⼦序列,应该是 [i + 1, j - 1] 区间内的那个最⻓回⽂⼦序列⾸尾填上
s[i] 和 s[j] ,此 dp[i][j] = dp[i + 1][j - 1] + 2

ii. 当⾸尾两个元素不「相同」的时候,也就是 s[i] != s[j] :此时这两个元素就不能同时添加在⼀个回⽂串的左右,那么我们就应该让 s[i] 单独加在⼀个序列的左边,或者让 s[j] 单独放在⼀个序列的右边,看看这两种情况下的最⼤值:
• 单独加⼊ s[i] 后的区间在 [i, j - 1] ,此时最⻓的回⽂序列的⻓度就是
dp[i][j - 1] ;
• 单独加⼊ s[j] 后的区间在 [i + 1, j] ,此时最⻓的回⽂序列的⻓度就是
dp[i+ 1][j] ;
取两者的最⼤值,于是 dp[i][j] = max(dp[i][j - 1], dp[i + 1][j])

3. 初始化
我们的初始化⼀般就是为了处理在状态转移的过程中,遇到的⼀些边界情况,因为我们需要根据状
态转移⽅程来分析哪些位置需要初始化。
根据状态转移⽅程 dp[i][j] = dp[i + 1][j - 1] + 2 ,我们状态表⽰的时候,选取的
是⼀段区间,因此需要要求左端点的值要⼩于等于右端点的值,因此会有两种边界情况:
i. 当 i == j 的时候, i + 1 就会⼤于 j - 1 ,此时区间内只有⼀个字符。这个⽐较好分析, dp[i][j] 表⽰⼀个字符的最⻓回⽂序列,⼀个字符能够⾃⼰组成回⽂串,因此此时 dp[i][j] = 1 ;

ii. 当 i + 1 == j 的时候, i + 1 也会⼤于 j - 1 ,此时区间内有两个字符。这样也
好分析,当这两个字符相同的时候, dp[i][j] = 2 ;不相同的时候, d[i][j] =0 。
对于第⼀种边界情况,我们在填表的时候,就可以同步处理。
对于第⼆种边界情况, dp[i + 1][j - 1] 的值为 0 ,不会影响最终的结果,因此可以不⽤考虑。

4. 填表顺序
因此我们的填表顺序应该是「从下往上填写每⼀⾏」,「每⼀⾏从左往右」

5. 返回值
需要返回dp[0][n - 1]

代码:

 int longestPalindromeSubseq(string s) {
          int n=s.size();
        

        //表示 i~j中最长子序列的长度
        vector<vector<int>> dp(n,vector<int>(n));

        for(int i=n-1;i>=0;i--)
        {
            dp[i][i]=1;
            for(int j=i+1;j<n;j++)
            {
                if(s[i]==s[j])
                {
                    dp[i][j]=dp[i+1][j-1]+2;
                }
                else
                {
                    dp[i][j]=max(dp[i+1][j],dp[i][j-1]);
                }
            }
        }
        return dp[0][n-1];

    }

在这里插入图片描述

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

链接: 1312. 让字符串成为回文串的最少插入次数

给你一个字符串 s ,每一次操作你都可以在字符串的任意位置插入任意字符。

请你返回让 s 成为回文串的 最少操作次数 。

「回文串」是正读和反读都相同的字符串。

示例 1:

输入:s = “zzazz”
输出:0
解释:字符串 “zzazz” 已经是回文串了,所以不需要做任何插入操作。
示例 2:

输入:s = “mbadm”
输出:2
解释:字符串可变为 “mbdadbm” 或者 “mdbabdm” 。
示例 3:

输入:s = “leetcode”
输出:5
解释:插入 5 个字符后字符串变为 “leetcodocteel” 。

1.状态表示*
. 状态表⽰:
关于「单个字符串」问题中的「回⽂⼦序列」,或者「回⽂⼦串」,我们的状态表⽰研究的对象⼀般都是选取原字符串中的⼀段区域 [i, j] 内部的情况。这⾥我们继续选取字符串中的⼀段区域来研究:
dp[i][j] 表⽰:s字符串 [i, j] 区间内的所有的⼦序列中,成为回⽂⼦串的最少插⼊次数

2.状态转移方程
关于「回⽂⼦序列」和「回⽂⼦串」的分析⽅式,⼀般都是⽐较固定的,都是选择这段区域的「左右端点」的字符情况来分析。因为如果⼀个序列是回⽂串的话,「去掉⾸尾两个元素之后依旧是回⽂串」,「⾸尾加上两个相同的元素之后也依旧是回⽂串」。因为,根据「⾸尾元素」的不同,可以分为下⾯两种情况:

i. 当⾸尾两个元素「相同」的时候,也就是 s[i] == s[j] :

  1. 那么 [i, j] 区间内成为回⽂⼦串的最少插⼊次数,取决于 [i + 1, j - 1] 区间
    内成为回⽂⼦串的最少插⼊次数;
  2. 若 i == j 或 i == j - 1 ( [i + 1, j - 1] 不构成合法区间),此时只有1~2个相同的字符, [i, j] 区间⼀定是回⽂⼦串,成为回⽂⼦串的最少插⼊次数是0。
    此时 dp[i][j] = i >= j - 1 ? 0 : dp[i + 1][j - 1] ;

ii. 当⾸尾两个元素「不相同」的时候,也就是 s[i] != s[j] :

  1. 此时可以在区间最右边补上⼀个 s[i] ,需要的最少插⼊次数是 [i + 1, j] 成为回
    ⽂⼦串的最少插⼊次数+本次插⼊,即 dp[i][j] = dp[i + 1][j] + 1 ;
  2. 此时可以在区间最左边补上⼀个 s[j] ,需要的最少插⼊次数是 [i, j + 1] 成为回
    ⽂⼦串的最少插⼊次数+本次插⼊,即 dp[i][j] = dp[i][j + 1] + 1 ;
    综上所述,状态转移⽅程为:

▪ 当 s[i] == s[j] 时: dp[i][j] = i >= j - 1 ? 1 : dp[i + 1][j -1] 。
▪ 当 s[i] != s[j] 时: dp[i][j] = min(dp[i + 1][j], dp[i][j - 1]) +1 。

3. 初始化
无需初始化

4. 填表顺序
因此我们的填表顺序应该是「从下往上填写每⼀⾏」,「每⼀⾏从左往右」

5. 返回值
需要返回dp[0][n - 1]

代码:

 int minInsertions(string s) {
          int n=s.size();

        vector<vector<int>> dp(n,vector<int>(n));

        for(int i=n-1;i>=0;i--)
        {
            for(int j=i+1;j<n;j++)
            {
                if(s[i]==s[j])
                {
                    dp[i][j]=dp[i+1][j-1];
                }
                else
                {
                    dp[i][j]=min(dp[i+1][j],dp[i][j-1])+1;
                }
            }
        }
        return dp[0][n-1];


    }

在这里插入图片描述

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

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

相关文章

C语言实现八种功能的通讯录(添加、删除、查找、修改、显示、排序、退出、清空)

通讯录功能概要及前提说明 此通讯录利用C语言完成&#xff0c;可以实现八种功能的通讯录&#xff08;添加、删除、查找、修改、显示、排序、退出、清空&#xff09; 代码由三部分组成&#xff0c;为什么要写成三部分而不写成一部分可以参考我以前的博客&#xff0c;如下&…

【Linux】Linux多线程

怎么理解线程线程的优缺点线程的二级页表线程用途怎么管理线程线程创建获取创建后的ID方法 线程等待线程终止分离线程线程ID及进程地址空间布局 怎么理解线程 通俗易懂的说&#xff0c;线程的运行是必须有进程给它打个基础。线程的运行是服用进程的代码及空间来进行运作的。 那…

[架构之路-223]:数据管理能力成熟度评估模型DCMM简介

目录 一、背景 二、评估依据 三、评估内容 四、主要适用对象 五、能力等级 六、不同层次的文件&#xff1a; 一、背景 信息技术与经济社会的交汇融合引发了数据爆发式增长。数据蕴含着重要的价值&#xff0c;已成为国家基础性战略资源&#xff0c;正日益对全球生产、流通…

会声会影和pr哪个好用? 2023年最新功能介绍解析

随着抖音、快手、B站等视频平台的普及&#xff0c;每个人都能成为视频创作者&#xff0c;视频剪辑软件成为自媒体创作的必备工具。一些新入门视频剪辑的小伙伴可能会疑惑&#xff0c;会声会影和PR软件哪个好呢&#xff1f;今天我将从核心功能、稳定性和性价比三个方面&#xff…

从中序遍历和后序遍历构建二叉树

题目描述 106. 从中序与后序遍历序列构造二叉树 中等 1.1K 相关企业 给定两个整数数组 inorder 和 postorder &#xff0c;其中 inorder 是二叉树的中序遍历&#xff0c; postorder 是同一棵树的后序遍历&#xff0c;请你构造并返回这颗 二叉树 。 示例 1: 输入&#xff1…

腾讯Mini项目课程前置学习笔记(第一轮)

Mini项目课程前置学习笔记&#xff08;第一轮&#xff09; 时间&#xff1a;5.20 ~ 5.23 项目基本介绍 项目 B. 指标监控服务重构 指标的收集与展示是后台系统监控中非常重要的一环&#xff0c;很可惜大而全的全链路监控方案并不适合我们&#xff0c;于是就有了本 mini 项目。…

cesium在vue中引入报错

npm install cesium1.95.0 找了很久各种办法都用了 最后就是降到这个版本。 在main.js中这样引入就可以运行起来了 import * as Cesium from cesium/Build/Cesium/Cesium.js; import cesium/Build/Cesium/Widgets/widgets.css; Vue.prototype.cesiumCesium 没出来是因为这个…

根据表名称快速查询表所有字段是否包含特定数据筛选

当前需要清理某个表中所有字段&#xff0c;检查是否有包含DEl字符的脏数据&#xff0c;如果字段比较少的直接根据字段查询即可&#xff0c;但是如果有几十个字段的话&#xff0c;逐个检查会很慢。 当前使用的方式是&#xff1a; 1&#xff1a;根据表名称获取当前表所有的字段 …

《信息系统项目管理师教程(第4版)》第1章至第5章 信息化发展、信息技术发展、信息系统治理、信息系统管理、信息系统工程 常见考点、知识点、思维导图、xmind

第一章至第五章多以选择题形式考察&#xff0c;分值在20分左右。已将考点、知识点整理成思维导图&#xff0c;可免费下载。以下是思维导图的部分截图&#xff1a; 第一章 信息化发展 第二章 信息技术发展 第三章 信息系统治理 第四章 信息系统管理 第五章 信息系统工程

代码随想录算法训练营第四十二天 | 动态规划 part 4 | 01背包问题(二维、一维滚动数组)、416. 分割等和子集

目录 01背包问题 二维代码 01背包问题&#xff08;一维滚动数组&#xff09;代码 416. 分割等和子集思路代码 01背包问题 二维 背包问题汇总&#xff1a; 二维数组dp——01背包五部曲 dp[i][j]表示从下标为[0-i]的物品里面任意取&#xff0c;放进容量为j的背包&#xff0c;价值…

Redis入门 (店铺营业状态设置) --苍穹外卖day4

目录 redis简介 redis下载与安装 redis服务启动与停止​编辑 redis数据类型 五种常用数据类型 各个类型特点 redis常用命令 字符串 哈希 列表 集合 有序集合 通用指令 ​在Java中操作Redis 导入坐标 编写配置类​ 通过RedisTem~对象操作 字符串 ​哈希 列…

什么是CDN

CDN是什么&#xff1f; 假设有一个IP为100.1.1.1的服务器网站&#xff0c;在没有CDN的情况下&#xff0c;PC先访问该服务器的DNS服务器&#xff0c;经过域名解析后再去访问服务器&#xff0c;如下图&#xff1a; 如果部署了CDN&#xff0c;这时候就有一个能识别CDN节点的DNS服…

经过打包后运行app.exe文件之后问题解决

项目文件经过python代码如何打包方法打包之后文件目录是下面这样的。 按照下面的路径运行app.exe文件报错&#xff1a; RuntimeError: Unable to open E:\face_detection\dist\app\face_recognition_models\models\shape_predictor_68_face_landmarks.dat [35816] Failed to…

AI在线工具分享

1、ChatGPT ChatGPT是一种由OpenAI训练的大型语言模型。它的原理是基于Transformer架构&#xff0c;通过预训练大量文本数据来学习如何生成人类可读的文本&#xff0c;然后通过接受输入并生成输出来实现对话。 ChatGPT的用途非常广泛&#xff0c;可以用于自然语言处理&#xf…

Seata入门系列【1】安装seata 1.7.1+nacos 2.1.1

1 介绍 Seata 是一款开源的分布式事务解决方案&#xff0c;致力于提供高性能和简单易用的分布式事务服务。Seata 将为用户提供了 AT、TCC、SAGA 和 XA 事务模式&#xff0c;为用户打造一站式的分布式解决方案。 Github: https://github.com/seata/seata 官方文档&#xff1a;h…

短期光伏发电量短期预测(Python代码,先对异常值处理,再基于XGBoost模型预测)

一.代码流程&#xff08;运行效果&#xff1a;短期光伏发电量短期预测&#xff08;Python代码&#xff0c;先对异常值处理&#xff0c;再基于XGBoost模型预测&#xff09;_哔哩哔哩_bilibili 模型流程&#xff1a; 导入所需的库&#xff0c;包括NumPy、Pandas、Matplotlib、Sea…

TS编译选项——TS文件编译后消除注释

在tsconfig.json文件中配置removeComments属性 {"compilerOptions": {// outDir 用于指定编译后文件所在目录"outDir": "./dist", // 将编译后文件放在dis目录下// 是否文件编译后移除注释"removeComments": true} } 左边是编写的t…

通过解读yolov5_gpu_optimization学习如何使用onnx_surgon

onnx实战一: 解析yolov5 gpu的onnx优化案例: 这是一个英伟达的仓库, 这个仓库的做法就是通过用gs对onnx进行修改减少算子然后最后使用TensorRT插件实现算子&#xff0c; 左边是优化过的, 右边是原版的。 通过这个案例理解原版的onnx的导出流程然后我们看英伟达是怎么拿gs来优化…

伦敦银如何选择最优的交易方法

经常有投资者会问&#xff0c;伦敦银投资中如何选择最好的方法呢&#xff1f;我们进行伦敦银投资&#xff0c;目的就是找到一个能够盈利的交易方法&#xff0c;它能够使我们大部分交易都是盈利&#xff0c;少部分交易亏损&#xff0c;但是可以将亏损控制在一定的范围之内&#…

Windows10关闭此电脑“桌面”“图片”“视频”“3D对象”“文档”等显示,只显示“设备与驱动器”

如何关闭下图"文件夹"等7个子文件夹&#xff0c;只显示“设备和驱动器”&#xff1f; 关闭步骤&#xff1a; 打开cmd,输入regedit打开注册表编辑器打开注册表编辑器后&#xff0c;定位到HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Explorer\My…