刷题之动态规划-回文串

前言

大家好,我是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];
    }
};
相关推荐
Swift社区3 小时前
LeetCode - #139 单词拆分
算法·leetcode·职场和发展
Kent_J_Truman3 小时前
greater<>() 、less<>()及运算符 < 重载在排序和堆中的使用
算法
IT 青年4 小时前
数据结构 (1)基本概念和术语
数据结构·算法
Dong雨4 小时前
力扣hot100-->栈/单调栈
算法·leetcode·职场和发展
SoraLuna4 小时前
「Mac玩转仓颉内测版24」基础篇4 - 浮点类型详解
开发语言·算法·macos·cangjie
liujjjiyun5 小时前
小R的随机播放顺序
数据结构·c++·算法
¥ 多多¥5 小时前
c++中mystring运算符重载
开发语言·c++·算法
trueEve6 小时前
SQL,力扣题目1369,获取最近第二次的活动
算法·leetcode·职场和发展
天若有情6736 小时前
c++框架设计展示---提高开发效率!
java·c++·算法
ahadee6 小时前
蓝桥杯每日真题 - 第19天
c语言·vscode·算法·蓝桥杯