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从二维数组变成了一维数组。
- Leetcode_palindrome-partitioning-ii
- Leetcode_Palindrome Partitioning II
- leetCode_Palindrome Partitioning II
- Leetcode_palindrome-partitioning
- Leetcode_Palindrome Partitioning
- LeetCode : Palindrome Partitioning II
- [leetcode] Palindrome Partitioning II
- leetcode:Palindrome Partitioning II
- Palindrome Partitioning II
- 【leetcode】Palindrome Partitioning II
- Palindrome Partitioning II
- leetcode - Palindrome Partitioning II
- Palindrome Partitioning II
- Palindrome Partitioning II
- [LeetCode]Palindrome Partitioning II
- [Leetcode]Palindrome Partitioning II
- [leetcode]Palindrome Partitioning II
- Palindrome Partitioning II
- 操作队列
- LeetCode Reverse Linked List
- XPath入门教程
- 使用wget 命令下载JDK的方法
- shell脚本中一些特殊符号
- Leetcode_Palindrome Partitioning II
- Atom编辑器折腾记_(14)JQ代码片段补全(插件:Jquery-snippets)
- 在交互式shell脚本中创建对话框
- Atom编辑器折腾记_(15)JS代码片段补全(插件:javascript-snippets)
- LeetCode_Surrounded Regions
- POJ 1188 解题报告
- LeetCode Reverse Linked List II
- Unity Manual之Network 网络
- mysql视图