刷题之动态规划-回文串

前言

大家好,我是jiantaoyab,开始刷动态规划的回文串类型相关的题目

动态规划5个步骤

  1. 状态表示 :dp数组中每一个下标对应值的含义是什么>dp[i]表示什么
  2. 状态转移方程: dp[i] 等于什么
  3. 1 和 2 是动态规划的核心步骤,第三步是初始化,保证填表的时候不越界
  4. 填表顺序:为了保证填写当前状态的时候,所需要的状态已经计算过
  5. 返回值

回文子串

题目分析

代码

cpp 复制代码
class Solution {
public:
    int countSubstrings(string s) {
      int n = s.size();
      int ret = 0;
      vector<vector<bool>> dp(n, vector<bool>(n));
      for(int i = n - 1; i >= 0; i--)
      {
        for(int j = i; j < n; j++) // i <= j
        {
          if(s[i] == s[j]) 
             dp[i][j] =  i + 1 < j ? dp[i + 1][j - 1] : true;
          if(dp[i][j]) ret++;
          
        }
      }

      return ret;
    }
};

最长回文子串

代码

动态规划版本

cpp 复制代码
class Solution {
public:
    string longestPalindrome(string s) {
        int n = s.size();
        vector<vector<bool>> dp(n, vector<bool>(n));
        int len = 1, begin = 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 + 1 < j ? dp[i + 1][j - 1] : true;
            if(dp[i][j] && j - i + 1 > len)
            {
               len = j - i + 1;
               begin = i;
               
            }
           
          }
        }
        return s.substr(begin, len);
    }
};

中心探测法

cpp 复制代码
class Solution {
public:
    string longestPalindrome(string s) {
     string RetStr="";
     for(int i=0;i<s.size();i++)
     {
         //回文串为奇数
         int left=i-1;
         int right=i+1;
         while(left>=0&&right<s.size()&&s[left]==s[right])
         {
             left--;
             right++;
         }
         if(RetStr.size()<right-left-1)
         {
             //babad
             //01234  letf=-1 i=1  right=3
             RetStr=s.substr(left+1,right-left-1);
         }
        //回文串为偶数
         left=i;
         right=i+1;
           while(left>=0&&right<s.size()&&s[left]==s[right])
         {
             left--;
             right++;
         }
          if(RetStr.size()<right-left-1)
         {
             
             RetStr=s.substr(left+1,right-left-1);
         }

     }
        return RetStr;
    }
};

分割回文串 IV

代码

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

      //枚举第二个字符串的起始位置和结束位置
      for(int i = 1; i < n - 1; i++) //前后留一个字符给第一个字符串
      {
        for(int j = i; j < n - 1; j++)//结束位置从i开始到n - 1
        {
            if(dp[0][i - 1] && dp[i][j] && dp[j + 1][n - 1] ) return true;
        }
      }
      return false;
    }
};

分割回文串 II

题目分析

代码

cpp 复制代码
class Solution {
public:
    int minCut(string s) {
      int n = s.size();
      vector<vector<bool>> is_pal(n, vector<bool>(n));
      int ret = 0;
      //把所有子串是不是回文串放到is_pal中
      for(int i = n - 1; i >= 0; i--)
      {
        for(int j = i; j < n; j++)
        {
          if(s[i] == s[j]) is_pal[i][j] = i + 1 < j ? is_pal[i + 1][j - 1] : true;
        }
      }
      vector<int> dp(n, INT_MAX);
      for(int i = 0; i < n; i++)
      {
        if(is_pal[0][i]) dp[i] = 0;
        // [0, i] 不是回文串
        else
        {
          for(int j = 1; j <= i; j++)
          {
            if(is_pal[j][i]) dp[i] = min(dp[i], dp[j - 1] + 1);
          }
        }
      }
      return dp[n - 1];
    }
};

最长回文子序列

题目分析

代码

cpp 复制代码
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--)
      {
        dp[i][i] = 1; // i == j
        for(int j = i + 1; j < n; j++)
        {
          if(s[i] == s[j])
          {
            if(i + 1 == j) dp[i][j] = 2;
            else if(i + 1 < j) 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];
    }
};

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

题目分析

cpp 复制代码
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] + 1, dp[i][j - 1] + 1);
          }
        }
      }
      return dp[0][n - 1];
    }
};
相关推荐
做科研的周师兄5 小时前
中国土壤有机质数据集
人工智能·算法·机器学习·分类·数据挖掘
来深圳5 小时前
leetcode 739. 每日温度
java·算法·leetcode
yaoh.wang5 小时前
力扣(LeetCode) 104: 二叉树的最大深度 - 解法思路
python·程序人生·算法·leetcode·面试·职场和发展·跳槽
hetao17338376 小时前
2025-12-21~22 hetao1733837的刷题笔记
c++·笔记·算法
醒过来摸鱼6 小时前
递归三种分类方法
算法
炽烈小老头6 小时前
【每天学习一点算法 2025/12/22】将有序数组转换为二叉搜索树
学习·算法
jghhh016 小时前
POCS(凸集投影)算法解决部分k空间数据缺失导致吉布斯伪影
算法
罗湖老棍子7 小时前
最小函数值(minval)(信息学奥赛一本通- P1370)
数据结构·c++·算法··优先队列·
LYFlied7 小时前
【每日算法】LeetCode 4. 寻找两个正序数组的中位数
算法·leetcode·面试·职场和发展
长安er7 小时前
LeetCode 62/64/5/1143多维动态规划核心题型总结
算法·leetcode·mybatis·动态规划