## 131. 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
.
A palindrome string is a string that reads the same backward as forward.
Example 1:
Input: s = "aab"
Output: [["a","a","b"],["aa","b"]]
Example 2:
Input: s = "a"
Output: [["a"]]
Constraints:
1 <= s.length <= 16
s
contains only lowercase English letters.The aim to partition the string into all possible palindrome combinations. To achieve this, we must generate all possible substrings of a string by partitioning at every index until we reach the end of the string. Example, abba
can be partitioned as ["a","ab","abb","abba"]
. Each generated substring is considered as a potential candidate if it a Palindrome.
Let's look at a few approaches to implement this idea.
Intuition
The idea is to generate all possible substrings of a given string and expand each possibility if is a potential candidate. The first thing that comes to our mind is Depth First Search. In Depth First Search, we recursively expand potential candidate until the defined goal is achieved. After that, we backtrack to explore the next potential candidate.
Backtracking incrementally build the candidates for the solution and discard the candidates (backtrack) if it doesn't satisfy the condition.
The backtracking algorithms consists of the following steps:
Algorithm
In the backtracking algorithm, we recursively traverse over the string in depth-first search fashion. For each recursive call, the beginning index of the string is given as start.
class Solution{
public:
vector<vector<string>> partition(string s){
vector<vector<string>> result;
vector<string> currentList;
dfs(result, s, 0, currentList);
return result;
}
voic dfs(vector<vector<string>> &result, string &s, int start, vector<string> ¤tList){
if(start >= s.length()) result.push_back(currentList);
for (int end = start; end < s.length(); end++){
if(isPalindrome(s, start, end)){
// add current substring in the currentList
currentList.push_back(s.substr(start, end-start+1));
dfs(result, s, end+1, currentList);
//backtrack and remove the current substring from currentList
currentList.pop_back();
}
}
}
bool isPalindrome(string &s, int low, int high){
while(low < high){
if(s[low++] != s[high--]) return false;
}
return true;
}
};
Complexity Analysis
Example, if = s = aaa
, the recursive tree can be illustrated as follows:
Hence, there could be possible substrings in the worst case. For each substring, it takes
time to generate substring and determine if it a palindrome or not. This gives us time complexity as
aaa
, the maximum depth of the recursive call stack is 3 which is equivalent to N.Intuition
This approach uses a similar Backtracking algorithm as discussed in Approach 1. But, the previous approach performs one extra iteration to determine if a given substring is a palindrome or not. Here, we are repeatedly iterating over the same substring multiple times and the result is always the same. There are Overlapping Subproblems and we could further optimize the approach by using dynamic programming to determine if a string is a palindrome in constant time. Let's understand the algorithm in detail.
Algorithm
A given string s starting at index \text{start}start and ending at index \text{end}end is a palindrome if following conditions are satisfied :
Let N be the length of the string. To determine if a substring starting at index start
and ending at index end
is a palindrome or not, we use a 2 Dimensional array dp
of size N·N
where,
dp[start][end]
= true, if the substring beginning at index start
and ending at index end
is a palindrome.
Otherwise, dp[start][end]
== false.
Also, we must update the dp
array, if we find that the current string is a palindrome.
class Solution{
public:
vector<vector<string>> partition(string s){
int len = s.length();
vector<vector<bool>> dp(len,vector<bool>(len,false));
vector<vector<string>> result;
vector<string> currentList;
dfs(result, s, 0, currentList, dp);
return result;
}
void dfs(vector<vector<string>> &result, string &s, int start, vector<string> ¤tList, vector<vector<bool>> &dp){
if(start >= s.length()) result.push_back(currentList);
for (int end = start; end < s.length(); end++){
if (s[start] == s[end] && (end-start <= 2 || dp[start+1][end-1])){
dp[start][end] = true;
currentList.push_back(s.substr(start, end-start+1));
dfs(result, s, end+1, currentList, dp);
currentList.pop_back();
}
}
}
};
Complexity Analysis
substr
as in Approach 1. However, we are eliminating one additional iteration to check if substring is a palindrome or not.This gives us total space complexity as
The Idea is simple:
loop through the string, check if substr(0, i) is palindrome. If it is, recursively call dfs()
on the rest of sub string: substr(i+1, length)
. keep the current palindrome partition so far in the 'path' argument of dfs()
. When reaching the end of string, add current partition in the result.
class Solution{
public:
vector<vector<string>> partition(string s){
vector<vector<string>> ret;
if(s.empty()) return ret;
vector<string> path;
dfs(0, s, path, ret);
return ret;
}
void dfs(int index, string& s, vector<string>& path, vector<vector<string>>& ret){
if(index == s.size()){
ret.push_back(path);
return;
}
for(int i = index; i < s.size(); ++i){
if(isPalindrome(s, index, i)){
path.push_back(s.substr(index, i - index + 1));
dfs(i+1, s, path, ret);
path.pop_back();
}
}
}
bool isPalindrome(const string& s, int start, int end){
while(start <= end){
if(s[start++] != s[end--])
return false;
}
return true;
}
};
此处可能存在不合适展示的内容,页面不予展示。您可通过相关编辑功能自查并修改。
如您确认内容无涉及 不当用语 / 纯广告导流 / 暴力 / 低俗色情 / 侵权 / 盗版 / 虚假 / 无价值内容或违法国家有关法律法规的内容,可点击提交进行申诉,我们将尽快为您处理。