动态规划之回文串问题

文章目录

  • 回文子串
  • 最长回文子串
  • 分割回文串 IV
  • 分割回文串 II
  • 最长回文子序列
  • 让字符串成为回文串的最少插入次数

回文子串

题目:回文子串

在这里插入图片描述
思路

  • 状态表示:dp[i][j]表示s字符串由ij是否是回文子串
  • 状态转移方程:
    • s[i] != s[j],则ij一定不是回文串;
    • s[i] == s[j]
      • i == j时,即只有一个字符,则一定是回文串,dp[i][j] = true
      • i + 1== j时,即有两个字符,则一定是回文串,dp[i][j] = true
      • 否则,说明ij中间还有其他的字符,此时如果i + 1j - 1是回文串,也就说明i到·j是回文串,所以dp[i][j] = dp[i + 1][j - 1]
  • 初始化:此题不用初始化
  • 填表顺序:由dp[i][j] = dp[i + 1][j - 1],知i + 1一定要在i前计算,所以从下往上填表;
  • 返回值:返回dp表中为true的个数

C++代码

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

        int ret = 0;
        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 || j == i + 1) ? true : dp[i + 1][j - 1];
                }
                if(dp[i][j]) ret++;
            }
        }
        return ret;
    }
};

最长回文子串

题目:最长回文子串

在这里插入图片描述
思路

此题和上题基本一致,只需在每次碰到 true时,判断当前回文子串的长度是否为大,如果是,则更新其起始下标以及长度;

C++代码

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

        int start = 0, len = 0;
        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 || j == i + 1) ? true : dp[i + 1][j - 1];
                }
                if(dp[i][j] && j - i + 1 > len)
                    start = i, len = j - i + 1;
            }
        }

        return s.substr(start, len);
    }   
};

分割回文串 IV

题目:分割回文串 IV

在这里插入图片描述
思路

依照第一题的解法将所有的子串都进行统计,遍历计算每个分割位置组成的3个子串是否都符合回文子串即可。

C++代码

class Solution 
{
public:
    bool checkPartitioning(string s) 
    {
        int n = s.size();
        vector<vector<bool>> dp(n, vector<bool>(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 == j || j == i + 1) ? true : dp[i + 1][j - 1];
                }
            }
        }

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

分割回文串 II

题目:添加链接描述

在这里插入图片描述
思路

  • 状态表示:
    dp[i]表示,字符串s[0, i]区间上的最长的子串,最少分割次数
  • 状态转移方程:
    • [0 - i]是回文串:0
    • [0 - i]不是回文串(0 < j <= i)[j, i]是否回文:
      • 是,dp[j - 1] + 1
      • 不是,min(dp[j - 1] + 1, dp[i]
  • 优化:用一个 dp表快速判断字符串中的子串是否回
  • 初始化:防止在求 min 时,0干扰结果,初始化为无穷大
  • 填表顺序: 从左往右
  • 返回值:dp[n - 1]

C++代码

class Solution 
{
public:
    int minCut(string s) 
    {
        int n = s.size();
        vector<vector<bool>> isPal(n, vector<bool>(n));
        for(int i = n - 1; i >= 0; i--)
            for(int j = i; j < n; j++)
                if(s[i] == s[j])
                    isPal[i][j] = (i == j || j == i + 1) ? true : isPal[i + 1][j - 1];

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

        return dp[n - 1];
    }
};

最长回文子序列

题目:最长回文子序列

在这里插入图片描述
思路

  • 状态表示:dp[i][j]表示字符串s [i, j]区间内的所有子序列中,最长的回文子序列的长度
  • 状态转移方程:
    • s[i] == s[j]
      • i == jdp[i][j] = 1
      • i + 1 == jdp[i][j] = 2
      • i + 1 < j dp[i][j] = dp[i + 1][j - 1] + 2
    • s[i] != s[j]dp[i][j] = max(dp[i][j - 1], dp[i + 1][j])
  • 初始化:特殊位置,状态转移方程已经考虑过了,不用初始化
  • 填表顺序:计算dp[i][j]时,需要用到dp[i + 1][j],所以从下往上,从左往右填
  • 返回值:dp[0][n - 1]

C++代码

class Solution 
{
public:
    int longestPalindromeSubseq(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])
                {
                    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][j - 1], dp[i + 1][j]);
                }
            }

        return dp[0][n - 1];
    }
};

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

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

在这里插入图片描述
思路

  • 状态表示:dp[i][j]表示字符串s [i, j]区间内的子串,让字符串成为回文串的最少插入次数

  • 状态转移方程:

    • s[i] == s[j]
      • i == jdp[i][j] = 0
      • i + 1 == jdp[i][j] = 0
      • i + 1 < j dp[i][j] = dp[i + 1][j - 1]
    • s[i] != s[j]
      • i位置的左边,即下标为i - 1位置添加一个s[j],此时只要保证[i, j - 1]成为回文串即可 ,dp[i][j] = dp[i][j - 1] + 1
      • j位置的右边,即下标为j + 1位置添加一个s[i],此时只要保证[i + 1, j]成为回文串即可 ,dp[i][j] = dp[i + 1][j] + 1
      • 综上,dp[i][j] = min(dp[i][j - 1], dp[i + 1][j]) + 1
  • 初始化:特殊位置,状态转移方程已经考虑过了,不用初始化

  • 填表顺序:计算dp[i][j]时,需要用到[i + 1]和[j - 1],所以从下往上,从左往右填

  • 返回值:dp[0][n - 1]

C++代码

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

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

【HarmonyOS】鸿蒙应用低功耗蓝牙BLE的使用心得 (一)

【HarmonyOS】鸿蒙应用低功耗蓝牙BLE的使用心得&#xff08;一&#xff09; 一、前言 鸿蒙官网文档中蓝牙部分&#xff0c;对于之前没有开发过蓝牙的同学&#xff0c;使用和查阅起来不是很方便。因为只是API的调用说明。并没有蓝牙整个调用流程的讲解&#xff0c;所以看起来会…

一个简单的例子,说明Matrix类的妙用

在Android、前端或者别的平台的软件开发中&#xff0c;有时会遇到类似如下需求&#xff1a; 将某个图片显示到指定的区域&#xff1b;要求不改变图片本身的宽高比&#xff0c;进行缩放&#xff1b;要求最大限度的居中填充到显示区域。 以下示意图可以简单描绘该需求 以Androi…

蚁剑连接本地木马文件报错

项目场景&#xff1a; 本地搭建php和蚁剑环境&#xff0c;连接本地木马文件ma.php 问题描述 使用蚁剑连接localhost时报错 错误{ "address":"127.0.0.1" "code":"ECONNREFUSED", "errno":"ECONNREFUSED", &qu…

网页上的视频怎么下载下来?三种方法

分享三个简单好用的网页视频下载工具&#xff0c;值得使用&#xff01; 1.IDM IDM 是一款可以提高下载速度达5倍的工具&#xff0c;同时具有恢复、调度和组织下载的功能。如果由于网络问题或意外的电源中断&#xff0c;程序将恢复未完成的下载。 IDM 还具有一个完全功能的站点…

使用 FastGPT 工作流实现 AI 赛博算卦,一键生成卦象图

最近那个男人写的汉语新解火遍了全网&#xff0c;那个男人叫李继刚&#xff0c;国内玩 AI 的同学如果不知道这个名字&#xff0c;可以去面壁思过了。 这个汉语新解的神奇之处就在于它只是一段几百字的提示词&#xff0c;效果却顶得上几千行代码写出来的应用程序。 这段提示词…

《虚拟现实的边界:探索虚拟世界的未来可能》

内容概要 在虚拟现实&#xff08;VR&#xff09;技术的浪潮中&#xff0c;我们见证了其从实验室的奇想逐渐走向日常生活的非凡旅程。技术发展的背后是不断突破的创新&#xff0c;早期的设备虽然笨重&#xff0c;但如今却趋向精致、轻巧&#xff0c;用户体验显著提升。想象一下…

无人机避障——4D毫米波雷达Octomap从点云建立三维栅格地图

Octomap安装 sudo apt-get install ros-melodic-octomap-ros sudo apt-get install ros-melodic-octomap-msgs sudo apt-get install ros-melodic-octomap-server sudo apt-get install ros-melodic-octomap-rviz-plugins # map_server安装 sudo apt-get install ros-melodic-…

推荐一个让线程池变的更简单的工具,轻量级的动态可监控线程池!(带私活源码)

背景 作为一个Java开发攻城狮&#xff0c;应用里少不了使用ThreadPoolExecutor 创建线程池&#xff0c;在使用的过程中你是否有以下痛点&#xff1a; 1、代码中创建了一个 ThreadPoolExecutor&#xff0c;但是不知道那几个核心参数设置多少比较合适 2、凭经验设置参数值&…

Fluent 后处理:动画制作

瞬态仿真中&#xff0c;动画制作是很重要的一个后处理步骤。Fluent中动画输出分为两步操作。 步骤 1&#xff1a;设置动画内容 在Fluent界面左侧树状菜单中的“solution animations”页面&#xff0c;设置动画内容。 其设置界面如下图所示。 1 合理设置动画帧的输出频率&…

机器人转人工时,开启实时质检(mod_cti基于FreeSWITCH)

文章目录 前言联系我们实现步骤1. 修改拨号方案2. 启用拨号方案 前言 在客户与机器人对话中&#xff0c;是不能开启质检功能的。因为机器人识别会与质检识别产生冲突。如果用户想通过机器人转接到人工时&#xff0c;开启质检功能&#xff0c;记录客户与人工之间的对话。应该如…

简记Vue3(二)—— computed、watch、watchEffect

个人简介 &#x1f440;个人主页&#xff1a; 前端杂货铺 &#x1f64b;‍♂️学习方向&#xff1a; 主攻前端方向&#xff0c;正逐渐往全干发展 &#x1f4c3;个人状态&#xff1a; 研发工程师&#xff0c;现效力于中国工业软件事业 &#x1f680;人生格言&#xff1a; 积跬步…

Linux字体更新 使用中文字体

问题描述&#xff0c;处理之前&#xff0c;中文乱码 处理后的结果 压缩需要上传的字体&#xff1a; 上传到LInux的字体目录&#xff0c;上传后解压出来 刷新字体&#xff1a; fc-cache -fv 测试是否正常 fc-list | grep "FontName"如果还不行 可以在代码里面指定字…

vivo 轩辕文件系统:AI 计算平台存储性能优化实践

在早期阶段&#xff0c;vivo AI 计算平台使用 GlusterFS 作为底层存储基座。随着数据规模的扩大和多种业务场景的接入&#xff0c;开始出现性能、维护等问题。为此&#xff0c;vivo 转而采用了自研的轩辕文件系统&#xff0c;该系统是基于 JuiceFS 开源版本开发的一款分布式文件…

2024年双11买什么最划算?双十一超全购物指南!

随着 2024 年双十一的脚步日益临近&#xff0c;消费者们又开始摩拳擦掌&#xff0c;准备在这个一年一度的购物狂欢节中尽情选购心仪的商品。然而&#xff0c;面对市场上琳琅满目的各类产品&#xff0c;很多人都会陷入迷茫&#xff1a;2024 年双 11 买什么最划算&#xff1f;为了…

【HTML】之基本标签的使用详解

HTML&#xff08;HyperText Markup Language&#xff0c;超文本标记语言&#xff09;是构建网页的基础。它不是一种编程语言&#xff0c;而是一种标记语言&#xff0c;用于描述网页的内容和结构。本文将带你了解HTML的基础知识&#xff0c;并通过详细的代码示例和中文注释进行讲…

nuxt数据库之增删改查,父组件子组件传值

nuxt学到数据库这里&#xff0c;就涉及到响应数据&#xff0c;父组件向子组件传值&#xff0c;子组件向父组件传值&#xff0c;最终还是需要掌握vue3的组件知识了。学习真的是一个长期的过程&#xff0c;不管学习了什么知识&#xff0c;有多少&#xff0c;都应该及时的记录下来…

Linux进程信号的处理

目录 一、信号的引入 二、信号的产生 1.通过键盘产生 &#xff08;1&#xff09;发送2号信号 &#xff08;2&#xff09;只能向前端进程传递信号 2.程序异常收到信号 &#xff08;1&#xff09;程序异常发送信号的现象 &#xff08;2&#xff09;程序异常发送信号的原因…

Nginx、Tomcat等项目部署问题及解决方案详解

目录 前言1. Nginx部署后未按预期显示结果1.1 查看Nginx的启动情况1.2 解决启动失败的常见原因 2. 端口开启问题2.1 Windows环境下的端口开放2.2 Linux环境下的端口开放 3. 重视日志分析3.1 Nginx日志分析3.2 Tomcat日志分析 4. 开发环境与部署后运行结果不同4.1 开发环境与生产…

Android 下载进度条HorizontalProgressView 基础版

一个最基础的自定义View 水平横向进度条&#xff0c;只有圆角、下载进度控制&#xff1b;可二次定制度高&#xff1b; 核心代码&#xff1a; Overrideprotected void onDraw(NonNull Canvas canvas) {super.onDraw(canvas);int mW getMeasuredWidth();int mH getMeasuredHei…

软考:CORBA架构

CORBA过时了吗 CORBA指南 个人小结&#xff1a; IPC&#xff0c;进程间通信&#xff0c;Socket应用在不同机器之间的通信 RPC是一种技术思想而非一种规范 但站在八九十年代的当口&#xff0c;简单来说&#xff0c;就是我在本地调用了一个函数&#xff0c;或者对象的方法&…