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 ...
随机推荐
- PHP常用函数整理
推荐网址:http://php.net/manual/zh/http://www.w3cschool.cc/php/php-ref-array.html 错误报告: error_reporting(E ...
- 手机端页面自适应之rem布局
W3C官网上是这样描述rem的--"font size of the root element" . rem布局在移动端发挥的比较好. 阿里团队高清方案: <script&g ...
- FSM(状态机)、HFSM(分层状态机)、BT(行为树)的区别
游戏人工智能AI中最常听见的就是这三个词拉: FSM 这个不用说拉,百度一大堆解释, 简单将就是将游戏AI行为分为一个一个的状态,状态与状态之间的过渡通过事件的触发来形成. 比如士兵的行为有“巡逻”, ...
- 第一届山东省ACM——Balloons(java)
Description Both Saya and Kudo like balloons. One day, they heard that in the central park, there wi ...
- Android Textview实现文字颜色渐变效果
最近做应用的时候遇到一个需求,一行文字的颜色需要一个渐变效果 如上所有 从左到有逐渐变化,自己写了一个demo实现上述效果 package com.huwei.example.test; import ...
- jq绑定事件的4种方式
jQuery提供了多种绑定事件的方式,每种方式各有其特点,明白了它们之间的异同点,有助于我们在写代码的时候进行正确的选择,从而写出优雅而容易维护的代码.下面我们来看下jQuery中绑定事件的方式都有哪 ...
- YII 错误 SQLSTATE[HY000] [2002] No such file or directory
在使用yii的yii\db\Connnection时发生错误 <?php namespace app\controllers; use yii\web\Controller; use yii\d ...
- linux第二天
由于今天公司事情比较多,今天基本没有自学.了解了一下type命令:主要是显示命令类型的命令.linux命令分为内置命令和外部命令两种.内置命令就shell内置的命令,外部命令,就是需要有系统存在一个名 ...
- [原创]webapp/css3实战,制作一个《炉石传说》宣传页
在移动网页,尤其是webapp中常需要用到大量的css3动画,来获得良好交互体验 我之前帮朋友做了一个,可惜没帮上忙现在和大家分享一下 目标是要做一个<炉石传说>游戏的介绍宣传页面,文字内 ...
- Json.net日期格式化
1. 全局设置,可以在App_Global中配置 JsonSerializerSettings setting = new JsonSerializerSettings(); JsonConvert. ...