Palindrome Partitioning系列

Palindrome Partitioning

 

Given a string s, partition s such that every substring of the partition is a palindrome.

Return all possible palindrome partitioning of s.

For example, given s = "aab",
Return

  [
    ["aa","b"],
    ["a","a","b"]
  ]

 方法一:暴力破解,直接深度搜索字串,直到找到所有解为止。假设字符串为S=a0a1a2a3a4a5...an,那么从下标0开始往后找回文字串,假设下标为i时有S[0...i]是回文,则将原问题化为子问题,即在S[i+1...n]中继续从头往后寻找回文字串,详细请看代码:

 1 class Solution {
 2 public:
 3     vector<vector<string>> partition(string s) {
 4         ans.clear();
 5         vector<string> vstrs;
 6         dfs(vstrs, s);
 7         return ans;
 8     }
 9     
10 private:
11     void dfs(vector<string>& vstrs, string s) {     //深度搜索
12         if( s.empty() ) {   //如果s为空串,则说明前面的切割出的字串均为回文
13             ans.push_back(vstrs);
14             return ;
15         }
16         for(int i=1; i<=s.length(); ++i) {  //依次从前往后开始切割
17             string tstr = s.substr(0, i);
18             if( ispalindrome(tstr) ) {  //如果被切割出的字符串是回文
19                 vstrs.push_back(tstr);  //存放结果
20                 dfs(vstrs, s.substr(i, s.length()-i));  //继续深搜未被切割的后面的字串
21                 vstrs.pop_back();   //pop结果
22             }
23         }
24     }
25     
26     //判断是否是回文
27     bool ispalindrome(const string& s) {
28         for(int i=0, j=s.length()-1; i<j; ++i,--j)
29             if( s[i] != s[j] ) return false;
30         return true;
31     }
32     
33 private:
34     vector< vector<string> > ans;   //保存切割后的结果
35 };

方法二:转为dp问题,另dp[i][j] 以 i 为起点,长度为 j 的的字串,则有

当 s[i] == s[i+j-1] 且 dp[i+1][j-2] == true 时 dp[i][j] = true;否则为false

当 j = 1 时 dp[i][j] = true;

最后通过dp二维数组,依然深度搜索字串,得出最后的结果,代码如下:

 

 1 class Solution {
 2 public:
 3     vector<vector<string>> partition(string s) {
 4         if( s.empty() )
 5             return vector< vector<string> >();
 6         vector< vector<bool> > dp(s.length(), vector<bool>(s.length()+1, false));   //行代表子串起始坐标,列代表字串长度
 7         for(int j=0; j<2; ++j)  //长度为0,1都认为是回文
 8             for(int i=0; i<s.length(); ++i)
 9                 dp[i][j] = true;
10         for(int j=2; j<=s.length(); ++j)    //从长度为2开始计算
11             for(int i=0; i<=s.length()-j; ++i)
12                 dp[i][j] = dp[i+1][j-2] && (s[i] == s[i+j-1]);
13         ans.clear();
14         vector<string> vstrs;
15         dfs(dp, vstrs, s, 0, s.length());   //深搜dp,找出满足条件的结果
16         return ans;
17     }
18     
19     //k为子串起始下标
20     void dfs(vector<vector<bool> >& dp, vector<string>& vstrs, string& s, int k, int n) {
21         if( k >= n ) {
22             ans.push_back(vstrs);
23             return ;
24         }
25         int len = n-k;  //子串[k...n-1]的长度
26         for(int i=1; i<=len; ++i) { //长度为1开始遍历
27             if( dp[k][i] ) {    //如果字串s[k...k+i-1]是回文
28                 vstrs.push_back(s.substr(k,i));
29                 dfs(dp, vstrs, s, k+i, n);
30                 vstrs.pop_back();
31             }
32         }
33     }
34     
35 private:
36     vector< vector<string> > ans;   //保存切割后的结果
37 };

Palindrome Partitioning II

 

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.

 

方法一:依然使用I所用的方法,直接超时,不能过大数据,代码如下:

 1 class Solution {
 2 public:
 3     int minCut(string s) {
 4         if( s.empty() )
 5             return 0;
 6         vector< vector<bool> > dp(s.length(), vector<bool>(s.length()+1, false));   //行代表子串起始坐标,列代表字串长度
 7         for(int j=0; j<2; ++j)  //长度为0,1都认为是回文
 8             for(int i=0; i<s.length(); ++i)
 9                 dp[i][j] = true;
10         for(int j=2; j<=s.length(); ++j)    //从长度为2开始计算
11             for(int i=0; i<=s.length()-j; ++i)
12                 dp[i][j] = dp[i+1][j-2] && (s[i] == s[i+j-1]);
13         ans = 0x3fffffff;
14         dfs(dp, 0, s.length(), 0);   //深搜dp,找出满足条件的结果
15         return ans;
16     }
17     
18     //k为子串起始下标
19     void dfs(vector<vector<bool> >& dp, int k, int n, int mincut) {
20         if( k >= n ) {
21             ans = min(ans, mincut-1);
22             return ;
23         }
24         int len = n-k;  //子串[k...n-1]的长度
25         for(int i=1; i<=len; ++i) { //长度为1开始遍历
26             if( dp[k][i] ) {    //如果字串s[k...k+i-1]是回文
27                 dfs(dp, k+i, n, mincut+1);
28             }
29         }
30     }
31     
32 private:
33     int ans;   //保存切割后的结果
34 };

 

方法二:首先求出dp[i][j],即从i开始长度为j的子串是否是回文。

接着假设mincuts[i]表示s[0...i]字串最小切割数可让子串均为回文,那么有

若s[0...i]是回文,则mincuts[i] = 0;

若s[0...i]不是回文,则mincuts[i] = min{  s[k+1...i]是回文 ? mincuts[k]+1 : mincuts[k] + i-k }  k=0,1,2,3...i-1

初始化:mincuts[0] = 0,时间复杂度为O(n2) + O(n2) = O(n2),代码如下:

 

 1 class Solution {
 2 public:
 3     int minCut(string s) {
 4         if( s.empty() ) return 0;
 5         vector< vector<bool> > dp( s.length(), vector<bool>(s.length()+1, false) );
 6         for(int i=0; i<s.length(); ++i) //长度为0,1的子串均认为是回文
 7             dp[i][0] = dp[i][1] = true;
 8         for(int j=2; j<=s.length(); ++j)    //计算各字串的回文情况
 9             for(int i=0; i<=s.length()-j; ++i)
10                 dp[i][j] = dp[i+1][j-2] && (s[i]==s[i+j-1]);
11         vector<int> mincuts(s.length(), 0); //初始化为0
12         for(int i=1; i<s.length(); ++i) {
13             if( dp[0][i+1] ) mincuts[i] = 0;    //如果s[0...i]是回文
14             else {  //循环遍历k,找出最小的切割数
15                 int tmin = 0x3fffffff;
16                 for(int k=0; k<i; ++k)
17                     if( dp[k+1][i-k] ) tmin = min(tmin, mincuts[k]+1);  //如果s[k+1...i]是回文,则为mincuts{k]+1
18                     else tmin = min(tmin, mincuts[k]+i-k);  //不是,则为mincuts[k]+i-k
19                 mincuts[i] = tmin;
20             }
21         }
22         return mincuts[s.length()-1];
23     }
24 };

 

 

 

posted on 2014-08-23 20:27  bug睡的略爽  阅读(155)  评论(0编辑  收藏  举报

导航