动态规划——回文串系列

动态规划--回文串系列 1.最长回文子串 2. 前言 动态规划回文串系列一直是我的一个痛点,今天上午看了书,本以为已经完全看懂了,结果下午闭书敲代码,敲了一下午还没有搞定,哎,果然代码不是靠看懂的,中间思考过程的艰深,只有敲过了代码才能感受到. 思路 dp五部曲: 1)确定dp[i][j]含义,这一步最重要,也是最难抉择的,为什么说最难抉择呢?到底dp[i][j]表示以下标[i,j]的字符串还是下标[i+1][j-1]的字符串呢?还是下标[i-1][j-1]的字符串呢?我们选择下标[i][j]的字... 阅读详情

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


 

class Solution
{
public:
    int countSubstrings(string s)
    {
        int n = s.size();
        vector<vector<bool>> dp(n, vector<bool>(n, false));
        int ret = 0;

        // 最开始填的是dp[n-1][n-1]
        for (int i = n - 1; i >= 0; i--)
        {
            for (int j = n - 1; j >= i; j--)
            {
                if (s[i] == s[j])
                {
                    if (i == j || i + 1 == j)
                        dp[i][j] = true;
                    else
                    {
                        dp[i][j] = dp[i + 1][j - 1];
                    }
                }

                if (dp[i][j])
                    ret++;
            }
        }
        return ret;
    }
};

// 可以用n^2级别的时间复杂度将所有子串是否是回文串保留到dp表中  这只是一个引子 虽然在本题效率不高 但是有些题想到了可以轻松将hard转为easy
// dp[i][j]:i、j维护子串的开始位置和结束位置 i、j分别像后面遍历 i外层 j遍历到n-1 之后i++ j只需要从i位置开始即可 因为j从头开始[j, i] 子串 而这个子串一定有一次[i, j]统计了 j=i开始遍历避免重复
// dp中的值为true或者false
// dp表中只有右上角的部分包括正对角线用到 因为i一定小于等于j

// 状态转移方程
// 在s[i] == s[j]的情况下若是i==j 那么一定是true i+1==j一定是true i、j之间存在其他元素 那么就需要看dp[i+1][j-1]是不是true即可 是则dp[i][j] = true 反之false

// 初始化 全部为false
// 就算用到i+1 j-1也不影响 因为这种情况一定不会越界 这种情况表明ij之间一定有其他元素

// 填表顺序 
// 需要用到左下角的dp 那么从下往上填表即可 保证上面填表时用到下面dp时一定有合法值

// 返回值 返回dp表中true的个数即可 因为dp[i][j]表示ij子串是不是会问换 而ij遍历了s中的所有子串


 

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

class Solution
{
public:
    string longestPalindrome(string s)
    {
        int n = s.size();
        vector<vector<bool>> dp(n, vector<bool>(n, false));
        int begin = 0, end = 0, maxlen = 0;
        for (int i = n - 1; i >= 0; i--)
        {
            for (int j = i; j < n; j++)
            {
                if (s[i] == s[j])
                {
                    if (i == j || i + 1 == j)
                    {
                        dp[i][j] = true;
                    }
                    else
                    {
                        dp[i][j] = dp[i + 1][j - 1];
                    }
                }
                if (dp[i][j])
                {
                    if (j - i + 1 > maxlen)
                    {
                        maxlen = j - i + 1;
                        begin = i;
                        end = j;
                    }
                }
            }
        }
        return s.substr(begin, end - begin + 1);
    }
};

// 和回文串个数那题一样 只不过需要记录最长的回文串的起始位置和结束位置即可

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

class Solution
{
public:
    bool checkPartitioning(string s)
    {
        int n = s.length();
        vector<vector<bool>> dp(n, vector<bool>(n, false));
        for (int i = n - 1; i >= 0; i--)
        {
            for (int j = i; j < n; j++)
            {
                if (s[i] == s[j])
                    dp[i][j] = i == j || i + 1 == j ? true : dp[i + 1][j - 1];
            }
        }
        // 枚举分割点
        for (int point1 = 0; point1 < n - 1; point1++)
        {
            if (!dp[0][point1])
                continue;
            for (int point2 = point1 + 2; point2 < n; point2++)
            {
                if (dp[point1 + 1][point2 - 1] && dp[point2][n - 1])
                {
                    return true;
                }
            }
        }
        return false;
    }
};

// 先使用找所有子串中的回文子串dp思想做一个预处理 找出所有回文子串
// 之后在这个二维dp表中找出可以拼接为完整字符串的三个回文子串 找得到返回true否则false
// 结果的三个回文子串之间的关系 首子串坐标必须是(0, j) 尾子串必须是(i, n-1) 遍历所有这些子串 找到一个坐标为(j+1, i-1)的中间子串并且三个长度加起来为n则表示可以分割 具体枚举第二个字符串的起始结束位置即可

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

class Solution
{
public:
    int minCut(string s)
    {
        int n = s.length();
        vector<vector<bool>> vis(n, vector<bool>(n, false)); // 记录ij之间子串是否是回文串 -- 预处理
        for (int i = n - 1; i >= 0; i--)
        {
            for (int j = i; j < n; j++)
            {
                if (s[i] == s[j])
                    vis[i][j] = i == j || i + 1 == j ? true : vis[i + 1][j - 1];
            }
        }

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

        return dp[n - 1];
    }
};

// 状态表示
// 定义dp[i]:0~i子串中分割为若干回文串的最少分割次数

// 状态转移方程
// 若是0~i子串本身就是回文串 那么dp[i] = 0
// 否则 假设在0~i之间切一下 j位置为分割点 若是j~i子串为回文串 那么dp[i] = 1 + dp[j-1]即可(0<j<=i) 为0则就是0~i子串 而已经知道不是回文串 所以这个点不需要遍历 遍历过程中取min(1+dp[j])即可
// 因为要频繁用到两个位置之间是否是回文串 可以预处理 用一个二维数组记录位置之间是否是回文串

// 初始化 使用到j-1 但是j不可能为0 所以没影响 但是dp[i] = min(dp[i], 1+dp[j-1])取最小值的原因 dp不能初始化为0 否则dp[i]全为0了 全部初始化为最大值

// 返回值 
// 返回dp[n-1]即可

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

class Solution
{
public:
    int longestPalindromeSubseq(string s)
    {
        int n = s.size();
        vector<vector<int>> dp(n, vector<int>(n, 1));

        int ret = 1;
        for (int i = n - 1; i >= 0; i--)
        {
            for (int j = i; j < n; j++)
            {
                if (s[i] == s[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] = max(dp[i + 1][j], dp[i][j - 1]);

                ret = max(ret, dp[i][j]);
            }
        }

        return ret;
    }
};

// 状态表示:
// dp[i][j] 表示以ij位置为边界的子串中所有回文子串中的最长长度

// 状态转移方程
// 若是s[i] == s[j] : i == j时 dp[i][j] = 1 ; i+1 == j 时 dp[i][j] = 2 ; 否则dp[i][j] = 2 + dp[i+1][j-1]
// 若是s[i] != s[j] : dp[i][j] = max(dp[i+1][j], dp[i][j-1]);

// 初始化 
// 的时候需要用到当前位置的左边和下面元素 因此只需要特殊处理左上角和右下角的元素 但是这两个位置s[i] == s[j] 进不去s[i] != s[j]的判断 因此不会越界

// 填表顺序
// 大方向从下往上 之后从左往右

// 返回值
// 返回dp表中最大的长度

1312. 让字符串成为回文串的最少插入次数 - 力扣(LeetCode)

class Solution 
{
public:
    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; j < n; j++)
            {
                if (s[i] == s[j])
                {
                    dp[i][j] = i + 1 < j ? dp[i+1][j-1] : 0;
                }
                else
                {
                    dp[i][j] = 1 + min(dp[i+1][j], dp[i][j-1]);
                }
            }
        }
        return dp[0][n-1];
    }
};


// 状态表示:
// dp[i][j] 表示让以i、j位置元素为边界的子串成为回文串的最少插入次数

// 状态转移方程:
// s[i] == s[j] : i == j || i + 1 == j dp[i][j] = 0 ; i + 1 < j dp[i][j] = dp[i+1][j-1]
// s[i] != s[j] : 首先得让边界先相同 可以在i左边加一个s[j] 或者在j右边加一个s[i] 对应的操作次数为 1 + dp[i][j-1] 1 + dp[i+1][j]

// 初始化 
// 全部初始化为0即可 画表带入状态转移方程都不会越界

// 填表顺序
// 从下往上 从左往右

// 返回值
// 返回dp[0][n-1]

【动态规划算法】-回文串问题题型(34-40题) 阅读详情

相关推荐

[特殊字符]最小切割分割回文串:动态规划真香系列!

📝 摘要: LeetCode 132题“分割回文串 II”要求找到将字符串分割为回文子串的最小切割次数。暴力DFS因指数复杂度不可行,转而采用动态规划两步走: 1️⃣ 预处理回文状态:用二维数组is_palindrome[i][j]缓存子串s[i:j+1]是否为回文,避免重复判断; 2️⃣ 状态转移:定义dp[i]为前i个字符的最小切割次数,若s[j:i+1]是回文,则dp[i] = min(dp[i], dp[j-1]+1)。 优势:时间复杂度优化至O(n²),核心思想是复用子问题结果+精准转移。同类回

Echo_Wish 112

动态规划-详解回文串系列问题

本文总结了回文字符串问题的五种常见变体及其动态规划解法:1. 最长回文子串(LeetCode5):通过dp[i][j]记录子串是否为回文,并跟踪最长回文;2. 回文子串计数(LeetCode647):类似方法统计所有回文子串数量;3. 分割回文串(LeetCode1745/132):先预处理回文信息,再枚举分割点或计算最少分割次数;4. 最长回文子序列(LeetCode516):处理不连续子序列的最长回文;5. 最少插入次数(LeetCode1312):通过动态规划计算使字符串成为回文的最少插入操作。所有问

nplplus的博客 1787

基于Pixhawk与OpenMV的无人机视觉引导精准降落系统设计与实现

本文详细介绍了基于Pixhawk飞控与OpenMV视觉模块的无人机精准降落系统设计与实现。系统通过OpenMV识别Apriltag标签,结合MAVLink通信将视觉数据发送给Pixhawk,实现厘米级精准降落。文章涵盖硬件连接、软件配置、核心代码逻辑解析及实战调试技巧,为无人机自动充电、物流配送等场景提供可靠解决方案。

weixin_29189377的博客 320

专题二十三_动态规划_回文串系列问题_算法专题详细总结

由上面给出的求解回文串的三种方法中,动态规划思想是一种极为重要的思路,通过这题就可以看出动态规划思路很清晰明了,可以很简单的就将hard转换为easy2.最⻓回⽂⼦串(medium)返回最长的一个回文子字符串回文串系列的题目还是非常好想的,只要弄明白一题,后面就是照搬原样即可;3.回⽂串分割IV(hard)将一个字符串分割成三块,如果这三块都是回文串,就直接返回true;否则返回false。

2301_80636070的博客 1134

TI C2000 DSP CLA实战:用F28069的协处理器实现ADC采样与PWM相位实时联动控制

本文详细介绍了如何利用TI C2000系列DSP的CLA协处理器在TMS320F28069上实现ADC采样与PWM相位的实时联动控制。通过CLA的零周期上下文切换和硬件级任务触发特性,显著提升了电机控制和数字电源应用的实时性能,特别适用于需要亚微秒级响应的场景。

weixin_30932215的博客 3968

斗罗大陆叙事体系与战斗系统设计解析

在文学创作与游戏设计中,世界观构建和战斗系统设计是两大核心技术要素。世界观作为故事发生的背景框架,需要融合东西方文化元素并建立量化标准,如《斗罗大陆》中武魂觉醒与魂环等级体系。战斗系统则需突破简单数值对抗,发展出武魂特性、魂技组合与环境互动的三维体系,其中魂导器技术的引入展现了科技与魔法的创新融合。这些设计原理在RPG游戏开发、网络文学创作等领域具有广泛应用价值,特别是对需要长期运营的IP作品,完善的系统设定能有效支撑剧情延展与商业化开发。本文以现象级作品为例,剖析其武魂拟态理论和魂师工业化构思如何成就经典

weixin_29291069的博客 250

动态规划:回文串系列

1、最长回文子串 寻找回文串的问题核心思想是:从中间开始向两边扩散来判断回文串 for 0 <= i < len(s): 找到以 s[i] 为中心的回文串;(奇数) 找到以 s[i] 和 s[i+1] 为中心的回文串 (偶数) 更新答案 class Solution { public String longestPalindrome(String s) { String result=""; for(int i=0;i&lt

啊哦的博客 595

从零搭建A股量化交易系统:开源框架选型与实战部署指南

本文详细介绍了从零搭建A股量化交易系统的完整流程,重点分析了开源框架VNPY和QMT的选型与实战部署。内容涵盖系统架构设计、策略开发、性能优化及实盘过渡方案,为开发者提供了一套完整的A股实盘量化交易解决方案,助力高效构建稳定可靠的量化交易系统。

sugar的博客 1276

动态规划专训6——回文串系列

动态规划题目中,常出现回文串相关问题,这里单独挑出来训练。

2301_80764270的博客 1004

多传感器标定:如何统一摄像头、雷达与IMU坐标?

多传感器标定:如何统一摄像头、雷达与IMU坐标?​ ,人工智能,计算机视觉,大模型,AI,本文详细阐述多传感器标定中统一摄像头、雷达与 IMU 坐标的方法。先介绍传感器坐标系统、坐标统一必要性及变换数学基础,再分述摄像头与雷达、IMU 与摄像头、IMU 与雷达的标定原理、步骤、参数计算及结果验证,还讲解了多传感器坐标统一的整体流程,分析了标定常见问题及解决办法,介绍了常用标定工具,结合实际案例说明应用,探讨了标定精度的影响因素、提升方法及发展趋势,为相关领域提供了全面的多传感器标定指导。​

不踩坑,不知道坑有多深;不总结,踩过的坑白踩。 12万+

即插即用系列(代码实践) | WACV 2024 CSAM:面向各向异性医学图像分割的 2.5D 跨切片注意力模块

文章摘要: 论文《CSAM: A 2.5D Cross-Slice Attention Module for Anisotropic Volumetric Medical Image Segmentation》提出了一种解决医学图像各向异性问题的创新模块CSAM。针对MRI/CT数据中切片间分辨率差异大的挑战,该模块通过2.5D跨切片注意力机制,结合2D卷积的轻量性和3D上下文感知能力。核心包括语义注意力(通道级)、位置注意力(空间级)和跨切片注意力(支持不确定性建模),能在几乎不增加参数量的情况下有效捕捉

分享顶会顶刊论文即插即用模块 106

动态规划回文串问题系列一> 分割回文串 IV

【代码】动态规划回文串问题系列一> 分割回文串 IV。

robin_suli的博客 386

RT-DETR改进策略【损失函数篇】| 通过辅助边界框计算IoU提升检测效果(Inner_GIoU、Inner_DIoU、Inner_CIoU、Inner_EIoU、Inner_SIoU)

为了弥补现有 IoU 损失在不同检测任务中泛化性弱和收敛速度慢的问题,·Inner-IoU·通过引入比例因子 “ratio” 来控制辅助边界框的尺度大小,利用不同尺度的辅助边界框来计算损失,从而加速边界框回归过程。

Limiiiing的博客 1965

动态规划回文串问题系列一>回文串分割II

【代码】动态规划回文串问题系列一>回文串分割II。

robin_suli的博客 320

自动权重化图卷积网络(Auto-Weighted GCN)算法在反洗钱识别中的应用及代码实现

该算法通过自动学习节点之间的权重信息,能够更好地捕捉AML数据中的关系和结构,从而提高反洗钱识别的准确性和效果。传统的AML识别方法通常依赖于专家定义的规则和手动提取的特征,但这些方法在应对大规模和复杂的数据时存在一定的局限性。GCN通过在图上执行卷积操作来捕捉节点之间的关系和结构信息,从而实现对图数据的学习和表示。自动权重化图卷积网络是一种基于GCN的改进算法,能够自动学习节点之间的权重信息,从而更好地捕捉图中的关系。利用自动计算的权重值执行图卷积操作。根据节点之间的相似度,计算每个节点的权重。

syntax_api860的博客 376

IMSL CNL 7.0.0 (x86-64)Crack

IMSL CNL 7.0.0 (x86-64)Crack intel的算法库破解文件,这是C++版本的破解文件

回文串系列动态规划附马拉车算法原理及实现

1. 回文子串(统计个数) 2. 最长回文子串(找最长连续回文) 3. 分割回文串 IV(分割为3个非空回文子串) 4. 分割回文串 II(最少分割次数使子串全为回文) 5. 最长回文子序列(找最长非连续回文子序列) 6. 让字符串成为回文串的最少插入次数(插入字符造回文)

分享 C/C++、Linux、网络的学习历程与实操心得~ 不追求一蹴而就,只坚持日积月累。未来还将拓展更多技术领域,愿与所有热爱技术的伙伴一起,在探索中成长,在坚持中进步! 1195

汉书HE8,好用的汇编代码编写工具

汉书HE8,好用的汇编代码编写工具早期编写汇编代码所用功能强大

动态规划专题:回文串系列问题的深度解析与统一解法

如果此时我们的isPal[j] [i]是true的话,就说明我们j到i这段是回文的,那么我们就更新下dp[i]了,看看我们此时的是dp[i]的值小还是dp[j-1]+1的值小。=s[j]的话,那么有两种情况,一种就是我们在左边补上一个s[j]那么就和右边的j回文上了,那么我们就处理(i,j-1)这个区间就行了。如果在s[i]=s[j]的情况下,dp[i+1] [j-1]的状态是true的话,那么就说明dp[i] [j]是true的。

2301_80863610的博客 7459

android 蓝牙通讯demo

android 下蓝牙通讯demo,实现了发现蓝牙,使能蓝牙,通过蓝牙发送消息。

pscad IEEE标准系统搭建说明

pscad IEEE标准系统搭建说明,包含典型的IEEE 9节点、14节点、30节点、39节点和118节点系统。内含标准测试系统的原始数据和潮流结果。

动态规划-回文串系列——1312.让字符串变成回文串的最小插入次数

这里首先判断两端字符是否相同,如果相同则需要判断[i,j]区间字符个数,然后向中间移动取dp表的值,反之不相同则需要对左插与右插两种情况取min值。一维dp表无法存储任意区间内将字符串变为回文子串的最小插入次数,所以使用二维dp表存储将[i,j]区间的字符串变为回文子串的最小插入次数。dp表只有中间对角线与中间对角线的右上方对角线两条路线可能会用到下三角的值,但是下三角全为0不影响填表,因此不用初始化。将[i,j]区间的字符串变为回文子串的最小插入次数。

2301_80689220的博客 469

【力扣系列题目】最后一块石头的重量 分割回文串 验证回文串 等差数列划分{最大堆 背包 动态规划}

【力扣系列题目】最后一块石头的重量 分割回文串 验证回文串 等差数列划分{最大堆 背包 动态规划}

Ape's IT Blog 1101

动态规划(2)---回文串/子串系列题目

动态规划第一篇详见此博客,介绍了理论和股票买卖系列题目 题目示例 leetcode300. 最长递增子序列 给你一个整数数组 nums ,找到其中最长严格递增子序列的长度。 子序列是由数组派生而来的序列,删除(或不删除)数组中的元素而不改变其余元素的顺序。例如,[3,6,2,7] 是数组 [0,3,1,6,2,2,7] 的子序列。 法1.动态规划 思路分析 我们用dp[i]表示数组的前i个元素构成的最长上升子序列,如果要求dp[i],我们需要用num[i]和前面的数字一个个比较,如果比前面的任何一个数

All_In_gzx_cc的博客 414

【日常系列】LeetCode《30·动态规划总结》

注意:子序列可以不连续例如,回文串问题线性动态规划问题:一、输入为一个数组或者一个字符串:(1) . dp [ i ] 依赖于前面一个或者两个状态计算得到力扣 53. 最大子序和力扣 91. 解码方法力扣 152. 乘积最大子数组力扣 376. 摆动序列力扣 198. 打家劫舍力扣 213. 打家劫舍 II【新增】力扣 740. 删除并获得点数力扣 509. 斐波那契数力扣 70. 爬楼梯问题力扣 746. 使用最小花费爬楼梯【新增】力扣 413. 等差数列划分。

qq_42889517的博客 976

动态规划回文串问题系列一>回文子串

题目: 解析: 注意:字串和子数组差不多 状态表示: 状态转移方程: 初始化: 填表顺序: 返回值: 返回dp表里true的个数

robin_suli的博客 366

LeetCode刷题复盘笔记—一文搞懂动态规划之132. 分割回文串 II问题(动态规划系列第二十九篇)

LeetCode刷题复盘笔记—一文搞懂动态规划之132. 分割回文串 II问题(动态规划系列第二十九篇)的。动态规划中每一个状态一定是由上一个状态推导出来的,这一点就区分于贪心,贪心没有状态推导,而是从局部直接选最优的对于动态规划问题,可以拆解为如下五步曲,这五步都搞清楚了,才能说把动态规划真的掌握了!确定dp数组(dp table)以及下标的含义确定递推公式dp数组如何初始化确定遍历顺序举例推导dp数组这篇文章主要总结了使用动态规划解决132. 分割回文串 II问题,

Lucky_Alan_Gareth的博客 233

动态规划回文串问题系列一>最长回文子序列

【代码】动态规划回文串问题系列一>最长回文子序列。

robin_suli的博客 266

动态规划-回文串系列——516.最长回文子序列

判断回文子序列需要从两端开始判断,当两端相等就向中间判断,如果不等就需要更换区间并且取出最长回文串子序列的长度。填表时将对角线都初始化为1,下三角默认为0,因为即使用到了下三角的数值,0也不会影响填表,所以就不用进行初始化。

2301_80689220的博客 484

五、动规_回文串系列

对于每个子串,先判断其首尾字符是否相等,若相等,再根据子串长度分情况处理:当子串只有一个字符时,肯定是回文串;数组后,为了找出是否存在一种分割方式能将字符串分割成三个满足条件的回文子串,代码通过另外两层嵌套循环遍历所有可能的分割点。三是当子串长度大于 2 时,需要判断去掉首尾字符后的中间子串是否为回文串,若中间子串对应的。具有不同开始位置或结束位置的子串,即使是由相同的字符组成,也会被视作不同的子串。等于 1 时,表明子串有两个字符且这两个字符相等,该子串也是回文串,同样将。的子串是否为回文串。

YQ20210216的博客 794
上一篇: 传输层UDP、TCP
下一篇: 网络层协议IP、数据链路层、NAT详解
溪苏.
博客等级 码龄3年 995粉丝 138原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值