LeetCode 之 Palindrome Partitioning II(动态规划)
2015-08-03 10:58
483 查看
【问题描述】
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 =
Return
be produced using 1 cut.
1.【基础知识】
1)substr函数掌握模糊;
2)动规与贪心算法的回顾;
3)树的深搜和广搜的应用能力;
4)fill_n函数。
2.【屌丝代码】
卡壳的地方:
1.剩下一个元素可以不切,直接判定跳出(已解决);
2.动规,一次循环同时进行前向与后向回文判定,并且采用初次前削判定和初次后削判定(已解决);
3.贪心,每次都比较,得到当下可以最快回文的长度,只不过未能实现(已解决);
4.解决了全部短小用例,倒在了代码中那段长不拉几的字符串用例上;
5.屌丝算法思想:
1)前向搜索:
1.1)先检查去掉最后Num个元素是不是回文;
1.1.1)是,则判断余下的是不是回文串——不是则直接进入下一层循环,是则直接跳出循环;
1.1.2)不是,继续循环体;
1.2)检查去掉最前Num个元素是不是回文;
1.2.1)是,则判断余下的是不是回文串——不是则直接进入下一层循环,是则直接跳出循环;
1.2.2)不是,继续循环体;
1.3)Num++
1.4)得到最终count_a;
2)后向搜索:
将1.1与1.2调换执行,得到最终count_b;
3)比较count_a与count_b,返回最小值。
1)卡壳部分
不能解决的原因在于字符串太长,耗时也在1H以上,题目未解出来;
动规的数学式子未能很好定义提炼。
2)AC源码思想——动态规划
定义状态 f(i,j) 表示区间 [i,j] 之间最小的 cut 数,则状态转移方程为
f(i, j) = min {f(i, k) + f(k + 1, j)} , i ≤ k ≤ j,0 ≤ i ≤ j < n
这是一个二维函数,实际写代码比较麻烦。所以要转换成一维 DP。如果每次,从 i 往右扫描,每找到一个回文就算一次 DP 的话,就可以转换为
f(i) = 区间 [i, n-1] 之间最小的 cut 数
n 为字符串长度,则状态转移方程为
f(i) = min {f(j + 1) + 1} , i ≤ j < n
一个问题出现了,就是如何判断 [i,j] 是否是回文?每次都从 i 到 j 比较一遍?太浪费了,这里也是一个 DP 问题。
定义状态 P[i][j] = true if [i,j] 为回文
,那么
P[i][j] = ( str[i] == str[j] && P[i+1][j-1] )
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
1since the palindrome partitioning
["aa","b"]could
be produced using 1 cut.
1.【基础知识】
1)substr函数掌握模糊;
2)动规与贪心算法的回顾;
3)树的深搜和广搜的应用能力;
4)fill_n函数。
2.【屌丝代码】
卡壳的地方:
1.剩下一个元素可以不切,直接判定跳出(已解决);
2.动规,一次循环同时进行前向与后向回文判定,并且采用初次前削判定和初次后削判定(已解决);
3.贪心,每次都比较,得到当下可以最快回文的长度,只不过未能实现(已解决);
4.解决了全部短小用例,倒在了代码中那段长不拉几的字符串用例上;
5.屌丝算法思想:
1)前向搜索:
1.1)先检查去掉最后Num个元素是不是回文;
1.1.1)是,则判断余下的是不是回文串——不是则直接进入下一层循环,是则直接跳出循环;
1.1.2)不是,继续循环体;
1.2)检查去掉最前Num个元素是不是回文;
1.2.1)是,则判断余下的是不是回文串——不是则直接进入下一层循环,是则直接跳出循环;
1.2.2)不是,继续循环体;
1.3)Num++
1.4)得到最终count_a;
2)后向搜索:
将1.1与1.2调换执行,得到最终count_b;
3)比较count_a与count_b,返回最小值。
#include <vector> #include <iostream> #include <algorithm> #include <vector> #include <string> using namespace std; class Solution { public: int minCut(string s) { int len = s.length(); if(len<=1||IsPld(s)) return 0; int tmp_len(len),cot_a(0),cot_b(0); string tmp_str = s; /* for(i=len-1;i>0;i--) // 切几刀? 如:0,表示不切,原字符串就是一个回文串 { int *arr = (int*)malloc(sizeof(int)*(i+1)); arr[0] = 0; vector<string> subs; for(j=1;j<=i+1;j++) // 循环刀数 for(k>arr[j-1];k<) // 每一刀怎么切? 下刀点 // 下一刀要比上一刀大; // 第一刀不能比0小;第一刀不能大于串长减刀数; // 第k刀不能比len-k大; // 最后一刀不能比串长大; { s.substr } delete []arr; }*/ /* while(tmp_len) { if(IsPld(tmp_str.substr(0,tmp_len))) { cot_a++; tmp_str = tmp_str.substr(tmp_len,tmp_str.size()-tmp_len); tmp_len = tmp_str.size(); if(IsPld(tmp_str)) break; } else if(IsPld(tmp_str.substr(tmp_str.size()-tmp_len,tmp_len))) { cot_a++; tmp_str = tmp_str.substr(0,tmp_str.size()-tmp_len); tmp_len = tmp_str.size(); if(IsPld(tmp_str)) break; } else { tmp_len--; } } tmp_len = len; tmp_str = s; while(tmp_len) { if(IsPld(tmp_str.substr(tmp_str.size()-tmp_len,tmp_len))) { cot_b++; tmp_str = tmp_str.substr(0,tmp_str.size()-tmp_len); tmp_len = tmp_str.size(); if(IsPld(tmp_str)) break; } else if(IsPld(tmp_str.substr(0,tmp_len))) { cot_b++; tmp_str = tmp_str.substr(tmp_len,tmp_str.size()-tmp_len); tmp_len = tmp_str.size(); if(IsPld(tmp_str)) break; } else { tmp_len--; } } return min(cot_a,cot_b); */ while(tmp_len) { if(IsPld(tmp_str.substr(0,tmp_len))) { cot_a++; tmp_str = tmp_str.substr(tmp_len,tmp_str.size()-tmp_len); tmp_len = tmp_str.size(); if(IsPld(tmp_str)) break; } if(IsPld(tmp_str.substr(tmp_str.size()-tmp_len,tmp_len))) { cot_a++; tmp_str = tmp_str.substr(0,tmp_str.size()-tmp_len); tmp_len = tmp_str.size(); if(IsPld(tmp_str)) break; } tmp_len--; } tmp_len = len; tmp_str = s; while(tmp_len) { if(IsPld(tmp_str.substr(tmp_str.size()-tmp_len,tmp_len))) { cot_b++; tmp_str = tmp_str.substr(0,tmp_str.size()-tmp_len); tmp_len = tmp_str.size(); if(IsPld(tmp_str)) break; continue; } if(IsPld(tmp_str.substr(0,tmp_len))) { cot_b++; tmp_str = tmp_str.substr(tmp_len,tmp_str.size()-tmp_len); tmp_len = tmp_str.size(); if(IsPld(tmp_str)) break; continue; } tmp_len--; } return min(cot_b,cot_a); } bool IsPld(string s) { if(s.length()<=1) return true; int i(0),j(s.size()-1); while(i<j) { if(s[i]!=s[j]) return false; i++; j--; } return true; } }; int main() { string mystr = "adabdcaebdcebdcacaaaadbbcadabcbeabaadcbcaaddebdbddcbdacdbbaedbdaaecabdceddccbdeeddccdaabbabbdedaaabcdadbdabeacbeadbaddcbaacdbabcccbaceedbcccedbeecbccaecadccbdbdccbcbaacccbddcccbaedbacdbcaccdcaadcbaebebcceabbdcdeaabdbabadeaaaaedbdbcebcbddebccacacddebecabccbbdcbecbaeedcdacdcbdbebbacddddaabaedabbaaabaddcdaadcccdeebcabacdadbaacdccbeceddeebbbdbaaaaabaeecccaebdeabddacbedededebdebabdbcbdcbadbeeceecdcdbbdcbdbeeebcdcabdeeacabdeaedebbcaacdadaecbccbededceceabdcabdeabbcdecdedadcaebaababeedcaacdbdacbccdbcece"; cout<<mystr.substr(1,2)<<endl; // string.substr(首元素索引,子串长度) Solution mySln; int num = mySln.minCut(mystr); cout<<num<<endl; while(1); return 0; }3.【源码AC】
// LeetCode, Palindrome Partitioning II // 时间复杂度 O(n^2),空间复杂度 O(n^2) class Solution { public: int minCut(string s) { const int n = s.size(); int f[n+1]; bool p ; fill_n(&p[0][0], n * n, false); //the worst case is cutting by each char for (int i = 0; i <= n; i++) f[i] = n - 1 - i; // 最后一个 f =-1 for (int i = n - 1; i >= 0; i--) { for (int j = i; j < n; j++) { if (s[i] == s[j] && (j - i < 2 || p[i + 1][j - 1])) { p[i][j] = true; f[i] = min(f[i], f[j + 1] + 1); } } } return f[0]; } };4.【复盘】
1)卡壳部分
不能解决的原因在于字符串太长,耗时也在1H以上,题目未解出来;
动规的数学式子未能很好定义提炼。
2)AC源码思想——动态规划
定义状态 f(i,j) 表示区间 [i,j] 之间最小的 cut 数,则状态转移方程为
f(i, j) = min {f(i, k) + f(k + 1, j)} , i ≤ k ≤ j,0 ≤ i ≤ j < n
这是一个二维函数,实际写代码比较麻烦。所以要转换成一维 DP。如果每次,从 i 往右扫描,每找到一个回文就算一次 DP 的话,就可以转换为
f(i) = 区间 [i, n-1] 之间最小的 cut 数
n 为字符串长度,则状态转移方程为
f(i) = min {f(j + 1) + 1} , i ≤ j < n
一个问题出现了,就是如何判断 [i,j] 是否是回文?每次都从 i 到 j 比较一遍?太浪费了,这里也是一个 DP 问题。
定义状态 P[i][j] = true if [i,j] 为回文
,那么
P[i][j] = ( str[i] == str[j] && P[i+1][j-1] )
相关文章推荐
- Flash Builder4.6破解方案(亲测有效)(转)
- Android 微信下拉眼睛
- UVA - 10344 - 23 out of 5 (暴力)
- android XMPP即时通讯客户端
- POJ 1273 --Drainage Ditches【最大流模板 && dinic】
- hihocoder 第五十二周 高斯消元·二【高斯消元解异或方程 难点【模板】】
- 南邮 OJ 1032 三角形数
- shell判断文件
- 20150802厦门大学华为校园提前批招聘机试体验题一:记票统计
- QT快捷键
- 支付宝接口应用及错误整理
- 时间帮助类
- HBase - Java 客户端 | 那伊抹微笑
- 1037:Keep on Truckin'
- githubslidingmenu
- django rest framework quickstart
- 从优化到再优化,最长公共子串
- 从优化到再优化,最长公共子串
- 从优化到再优化,最长公共子串
- Android解决ScrollView嵌套ListView滑动冲突问题