【动态规划刷题 18】(hard)回文子串&& (hard)最长回文子串

简介: 【动态规划刷题 18】(hard)回文子串&& (hard)最长回文子串

1745. 分割回文串 IV

给你一个字符串 s ,如果可以将它分割成三个 非空 回文子字符串,那么返回 true ,否则返回 false 。

当一个字符串正着读和反着读是一模一样的,就称其为 回文字符串 。

示例 1:

输入:s = “abcbdd”

输出:true

解释:“abcbdd” = “a” + “bcb” + “dd”,三个子字符串都是回文的。

示例 2:

输入:s = “bcbddxy”

输出:false

解释:s 没办法被分割成 3 个回文子字符串。

解法:

算法思路:

题⽬要求⼀个字符串被分成「三个⾮空回⽂⼦串」,乍⼀看,要表⽰的状态很多,有些⽆从下⼿。

其实,我们可以把它拆成「两个⼩问题」:

i. 动态规划求解字符串中的⼀段⾮空⼦串是否是回⽂串;

ii. 枚举三个⼦串除字符串端点外的起⽌点,查询这三段⾮空⼦串是否是回⽂串。

那么这道困难题就免秒变为简单题啦,变成了⼀道枚举题

代码:

  bool checkPartitioning(string s) {
           int n=s.size();
        vector<vector<bool>> dp(n,vector<bool>(n));
        dp[0][0]=1;
        for(int j=1;j<n;j++)
        {
            dp[j][j]=1;
            for(int i=0;i<=j;i++)
            {
                if(s[i]==s[j])
                {
                    if(j==i+1) dp[i][j]=1;
                    if(j>i+1)  dp[i][j]=dp[i+1][j-1];
                }
            }
        }
        for(int i=1;i<n-1;i++)
        {
            for(int j=0;j<i;j++)
            {
                if(dp[0][j]&&dp[j+1][i]&&dp[i+1][n-1])
                return true;
            }
        }
        return false;
    }




925f331a7de941a7816b0e1d2df5356d.png

132. 分割回文串 II

给你一个字符串 s,请你将 s 分割成一些子串,使每个子串都是回文。

返回符合要求的 最少分割次数 。

示例 1:

输入:s = “aab”

输出:1

解释:只需一次分割就可将 s 分割成 [“aa”,“b”] 这样两个回文子串。

示例 2:

输入:s = “a”

输出:0

示例 3:

输入:s = “ab”

输出:1

算法思路:状态表⽰:

根据「经验」,继续尝试⽤ i 位置为结尾,定义状态表⽰,看看能否解决问题:

dp[i] 表⽰: s 中 [0, i] 区间上的字符串,最少分割的次数

1.状态表示*

根据「经验」,继续尝试⽤ i 位置为结尾,定义状态表⽰,看看能否解决问题:

dp[i] 表⽰: s 中 [0, i] 区间上的字符串,最少分割的次数⽂串。2.状态转移方程

状态转移⽅程⼀般都是根据「最后⼀个位置」的信息来分析:设 0 <= j <= i ,那么我们可以根据 j ~ i 位置上的⼦串是否是回⽂串分成下⾯两类:

i. 当 [j ,i] 位置上的⼦串能够构成⼀个回⽂串,那么 dp[i] 就等于 [0, j - 1] 区 间上最少回⽂串的个数+1,即 dp[i] = dp[j - 1] + 1 ;

ii. 当 [j ,i] 位置上的⼦串不能构成⼀个回⽂串,此时 j 位置就不⽤考虑。

3. 初始化

观察「状态转移⽅程」,我们会⽤到 j - 1 位置的值。我们可以思考⼀下当 j == 0 的时候,表⽰的区间就是 [0, i] 。如果 [0, i] 区间上的字符串已经是回⽂串了,最⼩的回⽂串就是 了, j 往后的值就不⽤遍历了。

因此,我们可以在循环遍历 j 的值之前处理 j == 0 的情况,然后 j 从 1 开始循环。

但是,为了防⽌求 min 操作时, 0 ⼲扰结果。我们先把表⾥⾯的值初始化为「⽆穷⼤」

4. 填表顺序

从左往右

5. 返回值

根据「状态表⽰」,应该返回 dp[n - 1]

代码:

 int minCut(string s) {
  int n=s.size();
        vector<vector<bool>> dp(n,vector<bool>(n));
        dp[0][0]=1;
        for(int j=1;j<n;j++)
        {
            dp[j][j]=1;
            for(int i=0;i<=j;i++)
            {
                if(s[i]==s[j])
                {
                    if(j==i+1)  dp[i][j]=1;
                    if(j>i+1)   dp[i][j]=dp[i+1][j-1];
                }
            }
        }
        vector<int> dp1(n,INT_MAX-500);
        dp1[0]=0;
        for(int i=1;i<n;i++)
        {
            if(dp[0][i]) dp1[i]=0;
            else
            {
                for(int j=1;j<=i;j++)
                {
                    if(dp[j][i])
                        dp1[i]=min(dp1[i],dp1[j-1]+1);
                }
            }
        }
        return dp1[n-1];
    }

fe7eaf3caead4172840b63c146c91238.png


相关文章
|
5月前
【每日一题Day175】LC1147段式回文 | 贪心 +双指针
【每日一题Day175】LC1147段式回文 | 贪心 +双指针
19 0
|
1月前
|
算法 测试技术
每日一题:LeetCode-LCR 007. 三数之和
每日一题:LeetCode-LCR 007. 三数之和
|
2月前
《LeetCode 热题 HOT 100》—— 两数相加
《LeetCode 热题 HOT 100》—— 两数相加
|
5月前
【每日一题Day170】LC1040移动石子直到连续 II | 双指针 贪心 数学
【每日一题Day170】LC1040移动石子直到连续 II | 双指针 贪心 数学
28 1
|
5月前
|
算法
【面试算法——动态规划 19】最长回文子序列&& (hard)让字符串成为回文串的最少插入次数
【面试算法——动态规划 19】最长回文子序列&& (hard)让字符串成为回文串的最少插入次数
|
5月前
|
算法
【面试算法——动态规划 21】不同的子序列(hard)&& 通配符匹配(hard)
【面试算法——动态规划 21】不同的子序列(hard)&& 通配符匹配(hard)
|
人工智能 算法 JavaScript
Leedcode 327.区间和的个数:hard
Leedcode 327.区间和的个数:hard
63 0
|
算法 Go Python
LeetCode46:全排列(八皇后)
LeetCode46:全排列(八皇后)
LeetCode46:全排列(八皇后)
LeetCode每日一题——532. 数组中的 k-diff 数对
给定一个整数数组和一个整数 k,你需要在数组里找到 不同的 k-diff 数对,并返回不同的 k-diff 数对 的数目。
55 0

热门文章

最新文章