LeetCode 132 Palindrome Partitioning II--In C++
2016-06-18 11:15
399 查看
思路:
因为做了上一道Palindrome Partitioning,所以一个很简单粗暴的做法就是在上题基础上修改,然而这注定是要TLE的。因为问题的需求已经不一样了,在这道题中只问切分多少次能够产生所有子串为回文的效果。全程只需要保留一个数字即可。
想到了动态规划。
考虑了很多状态的表示法,都不怎么可行。最后想到了用一个数组cp来表示在字符串s中角标i和i之后的部分需要切cp[i-1]次。
举例来讲,“aab”的边界条件就是cp[2] = 0,因为2所在的位置是'a'(从1开始计数)。含义是a之后的部分“b”需要切0次可以产生全回文的效果。而cp[3] = -1,即b之后的部分(不含b)需要切-1次产生全回文的效果。为什么要等于-1而不是0呢,这要从本算法的工作原理讲起。。。
算法工作过程:
以“aab”为例,先看看它的所有回文串
(0,0)中间为1表示“a”是一个回文串,(0,2)为1,就表示“aab”是一个回文串。这一点在上一题中应该已经明确了。
这时候我们用一个数组cp来记录i之后的所有部分切几次能形成全回文,这就是动态规划的含义了。cp数组要比s中字符个数多一个,因此cp[0]表示从s[0](包含)到s[2](包含)切几次能形成全回文。如本例中cp[0]就是1,表示最少切一次。
从最后一个字符s[i]开始扫,在上表里可以查到所有以s[i]为结尾的回文串,顺便能够得到区间开始的那个字符的角标,例如对于s[2]只有区间[2,2]满足要求,可以得到这个区间起始于s[2],这时候就可以更新一次cp[2]的值。根据cp的含义,cp[2]的值应该等于cp[3]的切分次数加1,加一是因为将[2,2]和[3,X]切开用了一次。这时候可以看到为什么cp[3]要等于-1了,因为b之后已经没有字符了。
还有一点就是cp[i]可能被多个值更新,因此每次更新时取最小值。
因为做了上一道Palindrome Partitioning,所以一个很简单粗暴的做法就是在上题基础上修改,然而这注定是要TLE的。因为问题的需求已经不一样了,在这道题中只问切分多少次能够产生所有子串为回文的效果。全程只需要保留一个数字即可。
想到了动态规划。
考虑了很多状态的表示法,都不怎么可行。最后想到了用一个数组cp来表示在字符串s中角标i和i之后的部分需要切cp[i-1]次。
举例来讲,“aab”的边界条件就是cp[2] = 0,因为2所在的位置是'a'(从1开始计数)。含义是a之后的部分“b”需要切0次可以产生全回文的效果。而cp[3] = -1,即b之后的部分(不含b)需要切-1次产生全回文的效果。为什么要等于-1而不是0呢,这要从本算法的工作原理讲起。。。
算法工作过程:
以“aab”为例,先看看它的所有回文串
(0,0)中间为1表示“a”是一个回文串,(0,2)为1,就表示“aab”是一个回文串。这一点在上一题中应该已经明确了。
这时候我们用一个数组cp来记录i之后的所有部分切几次能形成全回文,这就是动态规划的含义了。cp数组要比s中字符个数多一个,因此cp[0]表示从s[0](包含)到s[2](包含)切几次能形成全回文。如本例中cp[0]就是1,表示最少切一次。
从最后一个字符s[i]开始扫,在上表里可以查到所有以s[i]为结尾的回文串,顺便能够得到区间开始的那个字符的角标,例如对于s[2]只有区间[2,2]满足要求,可以得到这个区间起始于s[2],这时候就可以更新一次cp[2]的值。根据cp的含义,cp[2]的值应该等于cp[3]的切分次数加1,加一是因为将[2,2]和[3,X]切开用了一次。这时候可以看到为什么cp[3]要等于-1了,因为b之后已经没有字符了。
还有一点就是cp[i]可能被多个值更新,因此每次更新时取最小值。
int minCut(string s) { int m = s.size(); if (m == 0){ return 0; } bool ** dp = new bool*[m]; for (int i = 0; i < m; i++){ dp[i] = new bool[m]; } for (int i = m - 1; i >= 0; i--){ for (int j = 0; j < m; j++){ if (i>j){ dp[i][j] = false; continue; } else if (i == j){ dp[i][i] = true; continue; } if (j - i >= 2){//[i,j]要为回文,[i+1,j-1]必须要为回文,且i,j两个字符必须相同 dp[i][j] = dp[i + 1][j - 1] && s[i] == s[j]; } if (j - i == 1){ dp[i][j] = (s[i] == s[j]); } } } int* cp = new int[m+2]; for (int i = 0; i < m + 2;i++){ cp[i] = 99999999; } cp[m] = -1;//s串的最后一个字符,需要切-1次,之后的部分全为回文 cp[m - 1] = 0;//倒数第二个字符,需要切0次,之后的部分全为回文 for (int i = m; i >= 1;i--){ for (int j = i; j >= 1;j--){ if (dp[j-1][i-1]==true){//s[i]和s[j]之间为回文 int val = cp[i] + 1; cp[j - 1] = val < cp[j - 1] ? val : cp[j - 1];//如果有多个值在更新cp[j-1],取最小的 } } } int result = cp[0]; for (int i = 0; i < m; i++){ delete[] dp[i]; } delete[]dp; delete[] cp; return result; }
相关文章推荐
- 数据库链接字符串查询网站
- Flex字符串比较 还有Flex字符串操作
- Ruby中创建字符串的一些技巧小结
- ASP下经常用的字符串等函数参考资料
- 将字符串小写转大写并延时输出的批处理代码
- 将字符串转换成System.Drawing.Color类型的方法
- Lua源码中字符串类型的实现
- Lua性能优化技巧(四):关于字符串
- 字符串聚合函数(去除重复值)
- Ruby中的字符串编写示例
- 总结的5个C#字符串操作方法分享
- sqlserver中求字符串中汉字的个数的sql语句
- sql server字符串非空判断实现方法
- C#算法函数:获取一个字符串中的最大长度的数字
- VBS的字符串及日期操作相关函数
- C#实现将千分位字符串转换成数字的方法
- jquery 删除字符串最后一个字符的方法解析
- PowerShell实现在字符串中查找大写字母
- PowerShell中使用Out-String命令把对象转换成字符串输出的例子
- PowerShell中字符串使用单引号和双引号的区别