LeetCode.132 分割回文串 II

使用动态规划解决回文划分问题
这篇博客详细解析了如何运用动态规划方法解决LeetCode上的回文划分问题(Palindrome Partitioning II)。作者首先介绍了动态规划的基本思路,然后通过创建二维布尔数组记录子串是否为回文,并定义了一个表示子串结束位置的最小分割次数的数组。博客中还提供了具体的Java代码实现,包括如何初始化dp数组和计算最小分割次数。最后,通过示例字符串展示了算法的运行过程。

原题

https://leetcode-cn.com/problems/palindrome-partitioning-ii/

在这里插入图片描述

思路

动态规划
又是该死的动态规划

  • 先用dp数组来保存子串 [i, j] 是否为回文串
  • 再用f{j}函数来表示 j 下标对应结尾的字符串的最小分割次数
    • 需要考虑 j 是否会独立占用一次分割
    • 先按照需要独立占用一次分割来计算,也就是f[j] = f[j-1] + 1
    • 然后从0遍历到 j 的位置,判断是否有对应的 [i, j] 形成回文串,也就是 f[j] = Math.min(f[j], f[i-1]+1)

我这里参考了大佬的解题思路,给大佬粘过来,以表感谢🙏
https://leetcode-cn.com/problems/palindrome-partitioning-ii/solution/xiang-jie-liang-bian-dong-tai-gui-hua-ji-s5xr/

题解

package com.leetcode.code;

/**
 * @Description:
 * @ClassName: Code132
 * @Author: ZK
 * @Date: 2021/3/8 22:16
 * @Version: 1.0
 */
public class Code132 {

    public static void main(String[] args) {
        String s = "aab";
        minCut(s);

    }

//    动态规划
//    1。先用dp数组来保存子串 [i, j] 是否为回文串
//    2。再用f{j}函数来表示 j 下标对应结尾的字符串的最小分割次数
//        需要考虑 j 是否会独立占用一次分割
//        先按照需要独立占用一次分割来计算,然后遍历到 j 的位置,判断是否有对应的 [i, j] 形成回文串,也就是 f[j] = Math.min(f[j], f[i-1]+1);
    public static int minCut(String s) {
        int len = s.length();
        char[] cs = s.toCharArray();

//        动态规划,设置dp数组来保存子串 [i, j] 是否为回文串
        boolean[][] st = new boolean[len][len];
        for (int j = 0; j < len; j++) {
            for (int i = j; i >= 0; i--) {
//                当 [i, j] 只有一个字符时,必然是回文串
                if (i == j) {
                    st[i][j] = true;
                } else {
//                    当 [i, j] 长度为 2 时,满足 cs[i] == cs[j] 即回文串
                    if (j-i == 1) {
                        st[i][j] = cs[i]==cs[j];
                    } else {
//                        当 [i, j] 长度超过 2 时,满足 cs[i]==cs[j] && f[i+1][j-1]==true 即回文串
//                        st[i][j] = cs[i]==cs[j] && cs[i+1]==cs[j-1];
                        st[i][j] = cs[i]==cs[j] && st[i+1][j-1];
                    }
                }
            }
        }

//        设:f{i}函数 代表下标为 i 的字符为结尾的最小分割次数
        int[] f = new int[len];
        for (int j = 1; j < len; j++) {
//            如果 [0, j] 为一个回文串,则无序分割
            if (st[0][j]) {
                f[j] = 0;
            } else {
//                如果 [0, j] 不是一个回文串,那么则依赖于 f[j-1],即 f[j] = f[j-1]+1
//                注意:此时 j 是需要独立的占用一个分割次数,例如:"aabbc",j=4, f[j] = f[j-1]+1
//                备注:此时先按照 j 需要独立占用一个分割次数来计算,下边进行 min 计算
                f[j] = f[j-1] + 1;

//                但是:如果 j 不需要独立占用一个分割次数,例如:"aabb", j=3, f[j]=f[j-1]+1 则错误
//                此时则需要与前边的某个 i 形成区间 [i, j],使得 [i, j] 回文
                for (int i = 0; i < j; i++) {
                    if (st[i][j]) {
                        f[j] = Math.min(f[j], f[i-1]+1);
                    }
                }
            }
        }

        return f[len-1];
    }

}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

难过的风景

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值