Leetcode_Palindrome Partitioning II

来源:互联网 发布:剑灵捏脸数据fate 编辑:程序博客网 时间:2024/05/22 01:30

132. Palindrome Partitioning II

一、题目描述

这里写图片描述

跟之前 Palindrome Partitioning (http://blog.csdn.net/gldemo/article/details/47848763)题目类似,只是变成了返回字符串的最小切割数。

二、解决思路

如果还按照之前 Palindrome Partitioning 的思路,按理是可以解决这个问题,但是不能在有效时间内解决。

所以我们想到在判断是否回文时,是不是可以进行剪枝;于是剪枝的思路就是和当前割数和最小割数比较,如果已经大于最小割数,说明这一个深度没有必要下去了。

但是我们会发现还是超时,于是我们想在深度搜索的递归过程中,是否是有重复计算的元素;比如 ababa划分为 aba b a 和 a b a b a 时,倒数两个字符是进行了重复计算的。所以我们引入了备忘录去记录,避免重复计算。这就有了我们下边的递归代码;

同时我们也用了动态规划去解决这个问题。具体可以参照下面代码。

三、java代码

1. 递归代码

这里要注意使用备忘录去减少对重复记录的计算;比如 ababa划分为 aba b a 和 a b a b a 时,倒数两个字符是进行了重复计算的。

public class Solution {    int minCutNum;    public int minCut(String s) {        boolean[][] dp = new boolean[s.length()][s.length()];//dp[i][j]表示从i到j这一段字符串是否是回文        int[][] beiwang = new int[s.length()+1][s.length()+1]; //beiwang表示备忘录,beiwang[i][k]表示从位置i开始,已经划分k块的是否判断过了        minCutNum = Integer.MAX_VALUE;        //先对s判断dp[i][j] 动态规划 上对三角 同时从左下角开始,每行从对角线开始初始化        for(int i=s.length()-1; i>=0; i--) {            for(int j=i; j<s.length(); j++) {                dp[i][j] = s.charAt(i) == s.charAt(j) && (j-i < 2 || dp[i+1][j-1] );            }        }        //对其深度搜索dfs        track(0,0,s.length(),dp,beiwang);        return minCutNum - 1;    }    public void track(int i, int k, int len, boolean[][] dp, int[][] beiwang) {        if(beiwang[i][k] == 1)            return;        if(i == len) {            minCutNum = Math.min(minCutNum, k);            return;        }        beiwang[i][k] = 1;        for(int j=len-1; j>=i; j--) {            if(dp[i][j]==true && minCutNum > k)                track(j+1, k+1, len, dp, beiwang);        }    }}

2. 动规代码

同时使用备忘录的深度搜索也可以动态规划解决问题。因为递归的话很可能会栈溢出。下面给出动态规划实现和解释。

public class Solution {    //int minCutNum;    public int minCut(String s) {        boolean[][] dp = new boolean[s.length()][s.length()];//dp[i][j]表示从i到j这一段字符串是否是回文        //先对s判断dp[i][j] 动态规划 上对三角 同时从左下角开始,每行从对角线开始初始化        for(int i=s.length()-1; i>=0; i--) {            for(int j=i; j<s.length(); j++) {                dp[i][j] = s.charAt(i) == s.charAt(j) && (j-i < 2 || dp[i+1][j-1] );            }        }        int[] count = new int[s.length()+1]; //count[i]表示从i位置开始分成多少块        for(int i=s.length()-1; i>=0; i--) {            count[i] = Integer.MAX_VALUE;            for(int j=i; j<s.length(); j++) {                if(dp[i][j] == true)                    count[i] = Math.min(count[i],count[j+1]+1);            }        }        return count[0]-1;    }}//同时可以合并两个for循环,更简洁public class Solution {    //int minCutNum;    public int minCut(String s) {        boolean[][] dp = new boolean[s.length()][s.length()];//dp[i][j]表示从i到j这一段字符串是否是回文        int[] count = new int[s.length()+1]; //count[i]表示从i位置开始分成多少块        //先对s判断dp[i][j] 动态规划 上对三角 同时从左下角开始,每行从对角线开始初始化        for(int i=s.length()-1; i>=0; i--) {            count[i] = Integer.MAX_VALUE;            for(int j=i; j<s.length(); j++) {                dp[i][j] = s.charAt(i) == s.charAt(j) && (j-i < 2 || dp[i+1][j-1] );                if(dp[i][j] == true)                    count[i] = Math.min(count[i],count[j+1]+1);//计算从位置i开始的块数            }        }        return count[0]-1;    }}

总结:代码的巧妙之处的提升在于:

1. 从Palindrome Partitioning (http://blog.csdn.net/gldemo/article/details/47848763)中判断回文要求的一个函数变成动态规划利用二维数组来表示从 i 到 j 的字符串是否为回文。也是因为题目要求不一样。

2. 判断从位置 i 开始的分块数,从开始的深度搜索的递归算法转变成动态规划的算法,没有了栈溢出的可能。同时count从二维数组变成了一维数组。

0 0
原创粉丝点击