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

一、647. 回文子串 

题目链接/文章讲解:代码随想录

 思考:

1.确定dp数组(dp table)以及下标的含义

如果本题定义dp[i] 为 下标i结尾的字符串有 dp[i]个回文串的话:

会发现很难找到递归关系,dp[i] 和 dp[i-1] ,dp[i + 1] 看上去都没啥关系,因此本题要从回文字符串的性质着手。

可以找到一种递归关系:

也就是判断一个子字符串(字符串的下表范围[i,j])是否回文,依赖于,子字符串(下表范围[i + 1, j - 1])) 是否是回文,为了明确这种递归关系,dp数组要定义成一位二维dp数组

bool dp[i][j]:表示区间范围[i,j] (注意是左闭右闭)的子串是否是回文子串,如果是dp[i][j]为true,否则为false。

2.确定递推公式

整体上是两种情况,就是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;}
}

3.dp数组的初始化

dp[i][j]初始化为false

4.确定遍历顺序

从递推公式中可以看出,情况三是根据dp[i + 1][j - 1]是否为true,在对dp[i][j]进行赋值true的。dp[i + 1][j - 1] 在 dp[i][j]的左下角,如图:

从下到上,从左到右遍历,这样保证dp[i + 1][j - 1]都是经过计算的。

for (int i = s.size() - 1; i >= 0; i--) {  for (int j = i; j < s.size(); j++) {

5.举例推导dp数组

代码实现: 

class Solution {
public:int countSubstrings(string s) {vector<vector<bool>> dp(s.size(), vector<bool>(s.size(), false));int result = 0;for (int i = s.size() - 1; i >= 0; i--) {  // 注意遍历顺序for (int j = i; j < s.size(); j++) {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;}}}}return result;}
};
  • 时间复杂度:O(n^2)
  • 空间复杂度:O(n^2)

二、516.最长回文子序列

题目链接/文章讲解:代码随想录

思考:本题和回文子串思路其实差不多,但比求回文子串简单一点,因为情况少了一点

1.确定dp数组(dp table)以及下标的含义

dp[i][j]:字符串s在[i, j]范围内最长的回文子序列的长度为dp[i][j]。

2.确定递推公式

如果s[i]与s[j]相同,dp[i][j] = dp[i + 1][j - 1] + 2;

如果s[i]与s[j]不相同,dp[i][j] = max(dp[i + 1][j], dp[i][j - 1])

不相同说明s[i]和s[j]的同时加入 并不能增加[i,j]区间回文子序列的长度,那么分别加入s[i]、s[j]看看哪一个可以组成最长的回文子序列。

加入s[j]的回文子序列长度为dp[i + 1][j]。

加入s[i]的回文子序列长度为dp[i][j - 1]。

那么dp[i][j]一定是取最大的,即:dp[i][j] = max(dp[i + 1][j], dp[i][j - 1]);

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]);
}

3.dp数组的初始化

从递推公式:dp[i][j] = dp[i + 1][j - 1] + 2; 可以看出 递推公式是计算不到 i 和j相同时候的情况,所以需要手动初始化一下,当i与j相同,那么dp[i][j]等于1,其他情况dp[i][j]初始为0

vector<vector<int>> dp(s.size(), vector<int>(s.size(), 0));
for (int i = 0; i < s.size(); i++) dp[i][i] = 1;

4.确定遍历顺序

dp[i][j] 依赖于 dp[i + 1][j - 1] ,dp[i + 1][j] 和 dp[i][j - 1]

所以遍历i的时候一定要从下到上遍历,j可以正常从左向右遍历。

for (int i = s.size() - 1; i >= 0; i--) {for (int j = i + 1; j < s.size(); 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]);}}
}

5.举例推导dp数组

代码实现: 

class Solution {
public:int longestPalindromeSubseq(string s) {vector<vector<int>> dp(s.size(), vector<int>(s.size(), 0));for (int i = 0; i < s.size(); i++) dp[i][i] = 1;for (int i = s.size() - 1; i >= 0; i--) {for (int j = i + 1; j < s.size(); 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][s.size() - 1];}
};
  • 时间复杂度: O(n^2)
  • 空间复杂度: O(n^2)

三、动态规划总结篇

题目链接/文章讲解:代码随想录

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

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

SPA项目之主页面--数据表格的增删改查

SPA项目之主页面--数据表格的增删改查 一.增删改查1.样式准备2.增加3.删除4.修改5.查询二.表单验证1.在表单中使用验证规则 一.增删改查 1.样式准备 <template><div class"books" style"padding: 20px;"><el-form :inline"true"…

深度学习基础知识 学习率调度器的用法解析

深度学习基础知识 学习率调度器的用法解析 1、自定义学习率调度器**&#xff1a;**torch.optim.lr_scheduler.LambdaLR2、正儿八经的模型搭建流程以及学习率调度器的使用设置 1、自定义学习率调度器**&#xff1a;**torch.optim.lr_scheduler.LambdaLR 实验代码&#xff1a; i…

31 数据分析(中)numpy介绍

文章目录 工具excelTableauPower Queryjupytermatplotlibnumpy安装导入包快速掌握&#xff08;bushi&#xff09;array和list的相互转化 np的range多维数组的属性array的改变形状array升降维度array内元素的类型数和array的运算array之间的加减法认识轴切片条件与逻辑修改值app…

多测师肖sir_高级金牌讲师_python之作业006

&#xff08;已做)1、求出1 / 1 1 / 3 1 / 5……1 / 99的和 (1分之一1分之三1分支5…) 方法1&#xff1a; sum 0 for s in range(1,101,2): sum 1/s print(sum) 方法2&#xff1a; i1 sum0 while i<99: sum1/i i2 print(sum) 方法3&#xff1a; list1 [1/x for x i…

【业务功能篇 131】23种设计模式介绍

第一章 设计模式概述 1.1 代码质量好坏如何评价? 要想学习设计模式呢 我们就必须搞清楚设计模式到底在我们的编程过程中起到了怎样的作用,在编程世界中它处在一个什么样的位置,它到底是一种抽象的设计思想,还是一套具体的落地方案. 在学习设计模式之前呢 我们需要了解一下 代…

【C语言】文件的操作与文件函数的使用(详细讲解)

前言&#xff1a;我们在学习C语言的时候会发现在编写一个程序的时候&#xff0c;数据是存在内存当中的&#xff0c;而当我们退出这个程序的时候会发现这个数据不复存在了&#xff0c;因此我们可以通过文件把数据记录下来&#xff0c;使用文件我们可以将数据直接存放在电脑的硬盘…

【运维笔记】Docker 部署Kibana-7.4.0(在线Docker版)

Docker 部署Kibana-7.4.0&#xff08;在线Docker版&#xff09; 一、准备工作&#xff1a; Centos 7.5 安装 Docker-24.0.6 详细步骤&#xff08;避坑版&#xff09;&#xff1a; https://blog.csdn.net/seesun2012/article/details/133674191注意1&#xff1a;本文的命令使用…

C语言:选择+编程(每日一练Day9)

目录 选择题&#xff1a; 题一&#xff1a; 题二&#xff1a; 题三&#xff1a; 题四&#xff1a; 题五&#xff1a; 编程题&#xff1a; 题一&#xff1a;自除数 思路一&#xff1a; 题二&#xff1a;除自身以外数组的乘积 思路二&#xff1a; 本人实力有限可能对…

时间提醒软件哪个好用?规划时间管理用哪一款提醒工具

在现代繁忙的工作生活中&#xff0c;时间成了我们最宝贵的资源之一。在时间快速流失的时代&#xff0c;我们需要一款能够有效管理工作计划的软件&#xff0c;特别是在电脑上进行记录和提醒。敬业签&#xff0c;作为一款值得信赖的时间管理工具&#xff0c;为我们的工作提供了高…

一文带你简单了解一下堡垒机是干嘛的!

随着国家对网络安全的重视&#xff0c;随着等保政策的落地执行&#xff0c;越来越多的企业知道了堡垒机。但对于堡垒机的作用还不是很了解&#xff0c;很多人在问&#xff0c;堡垒机是干嘛的、这里我们小编就跟大家来简单唠唠。 首先我们来看看什么是堡垒机&#xff1f; 堡垒…

基于YOLO算法与intel深度相机三维测量(工件尺寸和物体尺寸)

目录 1.简介 1.1 intel D4系列深度相机 (D455) 1.2 yolo算法 2.功能实现 2.1构思&#xff1a; 2.2 主代码 这篇文章还是接着前面的几篇文章的项目延申&#xff0c;这个是最初的方案&#xff0c;因为太贵被否了。 1.简介 1.1 intel D4系列深度相机 (D455) Intel RealSen…

文心一言 VS 讯飞星火 VS chatgpt (111)-- 算法导论10.2 2题

二、用go语言&#xff0c;用一个单链表 L实现一个栈。要求操作 PUSH和 POP 的运行时间仍为 O(1)。 文心一言&#xff1a; 在 Go 语言中&#xff0c;我们可以用结构体来实现一个单链表&#xff0c;然后再用栈的相关操作。 以下是一个可能的实现方式&#xff1a; package mai…