Leetcode: Palindrome Partitioning II
参考:http://www.cppblog.com/wicbnu/archive/2013/03/18/198565.html
我太喜欢用dfs和回溯法了,但是这些暴力的方法加上剪枝之后复杂度依然是很高,显然不能达到题目的要求。
这个时候应该考虑动态规划,并且要复杂度尽量接近O(n^2)的算法。
下面这个方法更加简洁:自长到短找到回文串后,往后dfs,并记录递归深度表示并更新最小划分数。http://fisherlei.blogspot.com/2013/03/leetcode-palindrome-partitioning-ii.html
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",
Return 1 since the palindrome partitioning ["aa","b"] could be produced using 1 cut.
题解:
类似矩阵连乘的动归思路。
dp[i][j]=min(dp[i][k]+dp[k+1][j]+1), i<=k<j.
但是用这个方程的时间是O(n^3),简化dp[i][j]为dp[i],表示从0到i的minCut.
dp[i]=min(dp[k]+1, dp[k]+i-k), 0<=k<i.
(s[k+1, i]是回文串) (s[k+1, i]不是回文串)
具体代码参见上述链接。
值得注意的是,计算是否为回文数的过程中也要用记忆化搜索才能减少重复比较的次数,it's smart~
MY CODE:
//
// ParlindromePartitioningII.cpp
// SJMcode
//
// Created by Jiamei Shuai on 13-8-31.
// Copyright (c) 2013年 Jiamei Shuai. All rights reserved.
// #include <vector>
#include <iostream>
#include <string.h>
#include <assert.h>
using namespace std; // 两处优化:
// 1.已经计算过的区间的最短划分次数用map纪录
// 2.回文串的判断结果也要用map记录 class Solution{
public:
int *minCutMat;
vector<vector<int> > map; int IsPalindrome(string &s, int i, int j)
{
if(i>j) return false;
if(map[i][j]!= -)
return map[i][j];
if(i==j)
return map[i][j]=; if(s[i]!=s[j])
return map[i][j]=;
else{
if(j-i==)
return map[i][j]=;
else
return map[i][j]=IsPalindrome(s,i+,j-);
}
} int minCut(string s) // 动态规划 d[i] = min{d[k]+1, d[k]+i-k}, 0<=k<i
{
int n = (int)s.length();
if(n==||n==)
return ; vector<int> min, vtmp;
min.clear();vtmp.clear();map.clear();
for(int i=; i<s.size(); i++)
{
min.push_back();
vtmp.push_back(-);
}
for(int i=; i<s.size(); i++)
map.push_back(vtmp); int tmp, ans;
for(int inter = ; inter<n; inter++)
{
if(IsPalindrome(s, , inter))
min[inter]=;
else{
ans = n+;
for(int k = ; k < inter; k++)
{
if(IsPalindrome(s, k+, inter))
tmp = min[k]+;
else
tmp = min[k] + inter - k;
if(tmp < ans)
ans = tmp;
}
min[inter] = ans;
}
}
return min[n-];
} // 较复杂的算法用dfs或者回溯法都太慢了,加上了所有的剪枝策略还是会超时
// 这种情况大多数都应该使用动态规划,要多总结,少犯错误。 int minCut2(string s) // 总是超时,复杂度太高
//这个方法相当于类似矩阵链乘的算法,dp[i][j] = min(dp[i][k]+dp[k+1][j]), i<=k<j,复杂度是O(n^3)
//可以简化dp[i][j]为dp[i],表示从0到i的minCut
{
int minCutNum = (int)s.size();
int len = (int)s.size(); minCutMat = new int[len*len]; // 注意new int[]而不是()
memset(minCutMat, -, len*len*sizeof(int)); vector<int> vtmp;
vtmp.clear();map.clear();
for(int i=; i<s.size(); i++)
vtmp.push_back(-);
for(int i=; i<s.size(); i++)
map.push_back(vtmp); // Notice: if the string need no split and itself a palindrome, how to handle it? 注意细节
if(IsPalindrome(s, , len-)) return ; split(s, , len-, minCutNum); delete []minCutMat; return minCutNum;
} int split(string &s, int begin, int end, int &minCutNum)
{
if(begin == end) return ; if(IsPalindrome(s, begin, end)) return ; int minCurrentSplit = (int)s.size();
int left,right; for(int i = begin; i < end; i++)
{
assert(begin*s.size()+i < s.size()*s.size());
assert(begin*s.size()+i < s.size()*s.size());
if(minCutMat[begin*s.size()+i] >= )
left = minCutMat[begin*s.size()+i];
else
{
left = split(s, begin, i, minCutNum);
minCutMat[begin*s.size()+i] = left;
}
if(left >= minCutNum) { return <<;} if(minCutMat[(i+)*s.size()+end] >= )
right = minCutMat[(i+)*s.size()+end];
else
{
right = split(s, i+, end, minCutNum);
minCutMat[(i+)*s.size()+end] = right;
}
if(right >= minCutNum) return <<; int tmp = left + + right; minCurrentSplit = min(tmp, minCurrentSplit); if(begin == && end == s.size()-) // outer loop
minCutNum = min(tmp, minCutNum);
}
return minCurrentSplit;
} }; int main()
{
Solution sln;
cout << sln.minCut("apjesgpsxoeiokmqmfgvjslcjukbqxpsobyhjpbgdfruqdkeiszrlmtwgfxyfostpqczidfljwfbbrflkgdvtytbgqalguewnhvvmcgxboycffopmtmhtfizxkmeftcucxpobxmelmjtuzigsxnncxpaibgpuijwhankxbplpyejxmrrjgeoevqozwdtgospohznkoyzocjlracchjqnggbfeebmuvbicbvmpuleywrpzwsihivnrwtxcukwplgtobhgxukwrdlszfaiqxwjvrgxnsveedxseeyeykarqnjrtlaliyudpacctzizcftjlunlgnfwcqqxcqikocqffsjyurzwysfjmswvhbrmshjuzsgpwyubtfbnwajuvrfhlccvfwhxfqthkcwhatktymgxostjlztwdxritygbrbibdgkezvzajizxasjnrcjwzdfvdnwwqeyumkamhzoqhnqjfzwzbixclcxqrtniznemxeahfozp"); return ;
}
附上更简洁的算法:
1: int minCut(string s) {
: int len = s.size();
: int D[len+];
: bool P[len][len];
: //the worst case is cutting by each char
: for(int i = ; i <= len; i++)
: D[i] = len-i;
: for(int i = ; i < len; i++)
: for(int j = ; j < len; j++)
: P[i][j] = false;
: for(int i = len-; i >= ; i--){
: for(int j = i; j < len; j++){
: if(s[i] == s[j] && (j-i< || P[i+][j-])){
: P[i][j] = true;
: D[i] = min(D[i],D[j+]+);
: }
: }
: }
: return D[]-;
: }
以及使用回溯+剪枝的方法:
: int minCut(string s) {
: int min = INT_MAX;
: DFS(s, , , min);
: return min;
: }
: void DFS(string &s, int start, int depth, int& min)
: {
: if(start == s.size())
: {
: if(min> depth-)
: min = depth-;
: return;
: }
: for(int i = s.size()-; i>=start; i--) //find the biggest palindrome first
: {
: if(isPalindrome(s, start, i))
: {
: DFS(s, i+, depth+, min);
: }
:
:
: }
: }
: bool isPalindrome(string &s, int start, int end)
: {
: while(start< end)
: {
: if(s[start] != s[end])
: return false;
: start++; end--;
: }
: return true;
: }
总结下来,要学会分析问题,不能一成不变的只用一个算法,可能会非常低效。
Leetcode: Palindrome Partitioning II的更多相关文章
- [LeetCode] Palindrome Partitioning II 解题笔记
Given a string s, partition s such that every substring of the partition is a palindrome. Return the ...
- LeetCode: Palindrome Partitioning II 解题报告
Palindrome Partitioning II Given a string s, partition s such that every substring of the partition ...
- [LeetCode] Palindrome Partitioning II 拆分回文串之二
Given a string s, partition s such that every substring of the partition is a palindrome. Return the ...
- [leetcode]Palindrome Partitioning II @ Python
原题地址:https://oj.leetcode.com/problems/palindrome-partitioning-ii/ 题意: Given a string s, partition s ...
- LeetCode:Palindrome Partitioning,Palindrome Partitioning II
LeetCode:Palindrome Partitioning 题目如下:(把一个字符串划分成几个回文子串,枚举所有可能的划分) Given a string s, partition s such ...
- leetcode@ [131/132] Palindrome Partitioning & Palindrome Partitioning II
https://leetcode.com/problems/palindrome-partitioning/ Given a string s, partition s such that every ...
- 【leetcode】Palindrome Partitioning II
Palindrome Partitioning II Given a string s, partition s such that every substring of the partition ...
- leetcode 131. Palindrome Partitioning 、132. Palindrome Partitioning II
131. Palindrome Partitioning substr使用的是坐标值,不使用.begin()..end()这种迭代器 使用dfs,类似于subsets的题,每次判断要不要加入这个数 s ...
- 【LeetCode】132. Palindrome Partitioning II
Palindrome Partitioning II Given a string s, partition s such that every substring of the partition ...
随机推荐
- Java Web学习笔记---用GET实现搜索引擎
今天做了一个实验,关于Servlet的.使用GET实现搜索引擎.因自己没有搜索引擎数据库,所以使用了Yahoo提供的Search API. 浏览效果如下图: 现在雅虎推出了新的Search API-- ...
- Echarts 饼图标题文字换行问题
var option = { title : { text: '数据来源', x:'center' }, tooltip : { trigger: 'item', formatter: "{ ...
- lcov和gcov的使用错误
编译使用的gcc版本和gcov的版本对不上的话,使用lcov和gcov的时候会报错 lcov的错误: [xx@localhost XXX]$ lcov --capture --directory co ...
- ASP.NET 验证码控件
public class ValidateCode : WebControl { /// <summary> /// 默认构造函数,暴露的属性接口 /// </summary> ...
- windows安装zookeeper-单机模式
zookeeper下载地址:http://zookeeper.apache.org/releases.html#download 本次使用的是3.4.9版本 前提:请安装JDK 安装: 创建安装目 ...
- javascript学习笔记(2)————this
//简单的学习JavaScript中this关键词 //this在于我简单的理解就是谁调用了当前方法(函数),this就指向谁 var a = 20; function fn1(){ this.a = ...
- 跟着百度学PHP[5]函数篇2-PHP中的特殊形式的函数
目录...................................................... .00x1 可变函数 在PHP里面如果说将“函数名称”赋予字符串类型的变量.在调用这个 ...
- css3伪类、伪元素选择器---nth-child()和nth-of-type()选择器的区别
p:nth-child(2) 要满足两个条件,1:选择的是p元素的父元素的第二个子元素 2:选择的第二个子元素必须是p元素,如果不满足,则将不显示 p:nth-of-type(2) 选择父元素下的 ...
- Oracle的动态性能视图[持续更新]
前言 .... v$version:查看数据库版本 其中 Oracle Database:指代数据库版本 PL/SQL:ORACLE对于标准SQL的超集,全称Procedural Language/S ...
- 各大浏览器内核特性及对应的Browserhacks举例
1.浏览器内核指的是什么? 简化的浏览器=用户界面+渲染引擎+js解析引擎+数据存储+网络部件 而通常所说的浏览器内核指的是页面渲染引擎(rendering engine). 2.渲染引擎 The r ...