算法题LC19:palindrome-partitioning-ii-动态规划

动态规划:
题目描述
给出一个字符串s,分割s使得分割出的每一个子串都是回文串
计算将字符串s分割成回文分割结果的最小切割数
例如:给定字符串s=“aab”,
返回1,因为回文分割结果[“aa”,“b”]是切割一次生成的。

Given a string s, partition s such that every substring of the partition is a palindrome.
Return the minimum cuts needed for a palindrome partitioning of s.

For example, given s =“aab”,
Return1since the palindrome partitioning[“aa”,“b”]could be produced using 1 cut.
输入描述

输出描述

示例1:
输入

输出
        
代码:

/**
 
* 动态规划的题,最主要就是写出状态转移方程
* 状态转移,其实就是怎么把一个大的状态表示为两个或者多个已知的状态
* 以此题为例,设f[i][j]为最小的切点数,那么有:
* 1、s[i][j]为回文字符串,则f[i][j] = 0;
* 2、增加一个切点p,将s[i][j]切割为两端s[i][p]、s[p+1][j],则f[i][j] = f[i][p]+f[p+1][j]
* 所谓的状态转移方程就是上面的式子
*
* 接着来看看怎么组织程序,先看看状态转移的思路:
* 以"aab"为例,"aab"明显不是回文串
* 所以 f("aab") = min( (f("a")+f("ab")) , (f("aa")+f("b")) ) + 1;
* f("a") = 0;
* f("ab") = f("a")+f("b") +1  = 0+0+1 = 1;
* f("aa") = 0;
* f("b") = 0;
* 即f("aab") = 1;
*
* 聪慧的你一定能看出来,这是一个递归调用的过程,计算f("ab")需要先计算f("a")、f("b")
* 用递归实现动态规划,在思路上是最简单的,大部分的题目都可以用这种方式解决
*
* 但是有一些数据变态的题目,加上测试机子给的堆栈太小,这种递归的算法很容易就爆栈了
* 我们需要用我们的聪明智慧,把递归的程序写为非递归的。
* 把解题思路从下往上看,假设我们先求出来了f("a"),f("b")
* 那么我们可以求出f("aa"),f("ab")
* 接着我们就可以得出答案f("aab")了
* 在这个过程中,我们需要牺牲空间(f[1000][1000])代替堆栈记录递归调用的返回值
* 而且这种方式有个好处,就是可以减少计算量
* 比如计算f("aab")时需要计算f("aa")+f("b")
* 计算f("ab")事需要计算f("a")+f("b")
* 这里就计算了两次f("b");
* 在第一次计算f("b")之后,将f("b")记录下来,可以减少一次计算量
* 动态规划本质上是暴力搜索,只不过咋这个暴力搜索的过程中,减少了不必要的计算,这样就提升了算法解决问题的速度
* 在一些题目中,你还可以根据题目减少某些分支的计算
* 比如只要判断这个字符串是回文串,就可以直接返回0,不需要一步步计算其中的子序列
*
*/
 
public class Solution {
    private String s;
    private int f[][] = new int[1000][1000];
 
    public int minCut(String s) {
        this.s = s;
        //先求解小段的子序列
        for(int t=0;t<=s.length();t++){
            for(int i=0,j=t;j<s.length();i++,j++){
                f[i][j] = compCut(i,j);
            }
        }
        return f[0][s.length()-1];
    }    
 
        // 状态转移方程的实现
    public int compCut(int i,int j) {
        if(isPalindrome(i,j)) return 0;
        int min = s.length();
        for(int p=i;p<j;p++) {
            int a = f[i][p];
            int b = f[p+1][j];
            a = a + b + 1;
            min = min<a?min:a;
        }
        return min;
     }
 
//判断是否回文串
    public boolean isPalindrome(int i,int j){
        while(i<j) {
        if(s.charAt(i) != s.charAt(j))
        return false;
        i++;
        j--;
    }
    return true;
    }
}

第二种:

public class Solution {
    public int minCut(String s) {
        if (s == null || s.length() == 0) {
            return 0;
        }
        int[] dp = new int[s.length()];
        dp[0] = 0;
        for (int i = 1; i < s.length(); i++) {
            dp[i] = isPalindrome(s.substring(0, i + 1)) ? 0 : i;
            if (dp[i] != 0) { //dp[i] = 0时不需要内循环
                for (int j = i; j > 0; j--) {
                    if (isPalindrome(s.substring(j, i + 1))) {
                        dp[i] = Math.min(dp[i], dp[j - 1] + 1);
                    }
                }
            }
        }
        return dp[s.length() - 1];
    }
     
    private static boolean isPalindrome(String s) {
        int begin = 0;
        int end = s.length() - 1;
        while (begin < end) {
            if (s.charAt(begin++) != s.charAt(end--)) {
                return false;
            }
        }
        return true;
    }
}
     
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值