题目:
回溯:找分割的字符串大小的组合,且每个组合都是回文
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 #include <vector> #include <string> using std::vector;using std::string;class Solution { private : void __partition(string &s, vector<vector<int > > &sum_vec, vector<int > &curr, int curr_sum) { int i, n = s.size (); if (curr_sum == n) { sum_vec.push_back (curr); return ; } for (i = 1 ; i <= n; i++) { if (curr_sum + i <= n && isPalindrome (s.substr (curr_sum, i))) { curr.push_back (i); __partition(s, sum_vec, curr, curr_sum + i); curr.pop_back (); } } } bool isPalindrome (string s) { int left = 0 , right = s.size () - 1 ; while (left < right) { if (s[left] != s[right]) return false ; left++; right--; } return true ; } public : vector<vector<string> > partition (string s) { int pos, n = s.size (); bool flag = false ; vector<vector<string> > ret; vector<vector<int > > sum_vec; vector<int > curr; __partition(s, sum_vec, curr, 0 ); for (vector<int > &combinatioin : sum_vec) { vector<string> curr_str_vec; pos = 0 ; for (int size : combinatioin) { curr_str_vec.push_back (s.substr (pos, size)); pos += size; } ret.push_back (curr_str_vec); } return ret; } };
然而上面这种方法判断回文会有超级多的重复计算,考虑动态规划
我们可以将字符串 s 的每个子串 s[i..j] 是否为回文串预处理出来,使用动态规划即可。设 f(i,j) 表示 s[i..j] 是否为回文串,那么有状态转移方程:
$$ f(i,j) = True, i≥j $$
$$ f(i,j) = f(i+1,j−1) ∧ (s[i]=s[j]) $$
优化后:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 #include <vector> #include <string> using std::vector;using std::string;class Solution { private : void __partition(string &s, vector<vector<int > > &sum_vec, vector<int > &curr, int curr_sum, vector<vector<bool > > &isPalindrome) { int i, n = s.size (); if (curr_sum == n) { sum_vec.push_back (curr); return ; } for (i = 1 ; i <= n; i++) { if (curr_sum + i <= n && isPalindrome[curr_sum][curr_sum + i - 1 ]) { curr.push_back (i); __partition(s, sum_vec, curr, curr_sum + i, isPalindrome); curr.pop_back (); } } } public : vector<vector<string> > partition (string s) { int pos, n = s.size (); vector<vector<string> > ret; vector<vector<int > > sum_vec; vector<int > curr; vector<vector<bool > > isPalindrome (n, vector <bool >(n, false )); for (int i = n - 1 ; i >= 0 ; i--) { for (int j = i; j < n; j++) { if (s[i] == s[j]) { if (j - i <= 2 ) isPalindrome[i][j] = true ; else isPalindrome[i][j] = isPalindrome[i + 1 ][j - 1 ]; } } } __partition(s, sum_vec, curr, 0 , isPalindrome); for (vector<int > &combinatioin : sum_vec) { vector<string> curr_str_vec; pos = 0 ; for (int size : combinatioin) { curr_str_vec.push_back (s.substr (pos, size)); pos += size; } ret.push_back (curr_str_vec); } return ret; } };
官方题解
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 class Solution {private : vector<vector<int >> f; vector<vector<string>> ret; vector<string> ans; int n; public : void dfs (const string& s, int i) { if (i == n) { ret.push_back (ans); return ; } for (int j = i; j < n; ++j) { if (f[i][j]) { ans.push_back (s.substr (i, j - i + 1 )); dfs (s, j + 1 ); ans.pop_back (); } } } vector<vector<string>> partition (string s) { n = s.size (); f.assign (n, vector <int >(n, true )); for (int i = n - 1 ; i >= 0 ; --i) { for (int j = i + 1 ; j < n; ++j) { f[i][j] = (s[i] == s[j]) && f[i + 1 ][j - 1 ]; } } dfs (s, 0 ); return ret; } };