LeetCode: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"] ]
分析:首先对字符串的所有子串判断是否是回文,设f[i][j] = true表示以i为起点,长度为j的子串是回文,等于false表示不是回文,那么求f[i][j]的动态规划方程如下:
-
当j = 1,f[i][j] = true;
-
当j = 2,f[i][j] = (s[i]==s[i+1]),其中s是输入字符串
-
当j > 2, f[i][j] = f[i+1][j-2] && (s[i] == s[i+j-1])(即判断s[m..n]是否是回文时:只要s[m+1...n-1]是回文并且s[m] = s[n],那么它就是回文,否则不是回文)
这一题也可以不用动态规划来求f,可以用普通的判断回文的方式判断每个子串是否为回文。 本文地址
求得f后,根据 f 可以构建一棵树,可以通过DFS来枚举所有的分割方式,代码如下:
1 class Solution { 2 public: 3 vector<vector<string>> partition(string s) { 4 // IMPORTANT: Please reset any member data you declared, as 5 // the same Solution instance will be reused for each test case. 6 vector< vector<string> >res; 7 int len = s.length(); 8 if(len == 0)return res; 9 //f[i][j] = true表示以i为起点,长度为j的子串是回文 10 bool **f = new bool*[len]; 11 for(int i = 0 ; i < len; i++) 12 { 13 f[i] = new bool[len+1]; 14 for(int j = 0; j < len+1; j++) 15 f[i][j] = 0; 16 f[i][1] = true; 17 } 18 for(int k = 2; k <= len; k++) 19 { 20 for(int i = 0; i <= len-k; i++) 21 { 22 if(k == 2)f[i][2] = (s[i] == s[i+1]); 23 else f[i][k] = f[i+1][k-2] && (s[i] == s[i+k-1]); 24 } 25 } 26 vector<string> tmp; 27 DFSRecur(s, f, 0, res, tmp); 28 for(int i = 0 ; i < len; i++) 29 delete [](f[i]); 30 delete []f; 31 return res; 32 } 33 34 void DFSRecur(const string &s, bool **f, int i, 35 vector< vector<string> > &res, vector<string> &tmp) 36 {//i为遍历的起点 37 int len = s.length(); 38 if(i >= len){res.push_back(tmp); return;} 39 for(int k = 1; k <= len - i; k++) 40 if(f[i][k] == true) 41 { 42 tmp.push_back(s.substr(i, k)); 43 DFSRecur(s, f, i+k, res, tmp); 44 tmp.pop_back(); 45 } 46 47 } 48 };
LeetCdoe: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. 本文地址
算法1:在上一题的基础上,我们很容易想到的是在DFS时,求得树的最小深度即可(遍历时可以根据当前求得的深度进行剪枝),但是可能是递归层数太多,大数据时运行超时,也贴上代码:
1 class Solution { 2 public: 3 int minCut(string s) { 4 // IMPORTANT: Please reset any member data you declared, as 5 // the same Solution instance will be reused for each test case. 6 int len = s.length(); 7 if(len <= 1)return 0; 8 //f[i][j] = true表示以i为起点,长度为j的子串是回文 9 bool **f = new bool*[len]; 10 for(int i = 0 ; i < len; i++) 11 { 12 f[i] = new bool[len+1]; 13 for(int j = 0; j < len+1; j++) 14 f[i][j] = 0; 15 f[i][1] = true; 16 } 17 for(int k = 2; k <= len; k++) 18 { 19 for(int i = 0; i <= len-k; i++) 20 { 21 if(k == 2)f[i][2] = (s[i] == s[i+1]); 22 else f[i][k] = f[i+1][k-2] && (s[i] == s[i+k-1]); 23 } 24 } 25 int res = len, depth = 0; 26 DFSRecur(s, f, 0, res, depth); 27 for(int i = 0 ; i < len; i++) 28 delete [](f[i]); 29 delete []f; 30 return res - 1; 31 } 32 void DFSRecur(const string &s, bool **f, int i, 33 int &res, int &currdepth) 34 { 35 int len = s.length(); 36 if(i >= len){res = res<=currdepth? res:currdepth; return;} 37 for(int k = 1; k <= len - i; k++) 38 if(f[i][k] == true) 39 { 40 currdepth++; 41 if(currdepth < res) 42 DFSRecur(s, f, i+k, res, currdepth); 43 currdepth--; 44 } 45 46 } 47 48 };