Given a string s partition string s such that every substring of partition is palindrome. Return all possible palindrome partition of string s.
Input : s = "aabaa"
Output : [ [ "a", "a", "b", "a", "a"] , [ "a", "a", "b", "aa"] , [ "a", "aba", "a"] , [ "aa", "b", "a", "a"] , [ "aa", "b", "aa" ] , [ "aabaa" ] ]
Explanation : Above all are the possible ways in which the string can be partitioned so that each substring is a palindrome.
Input : s = "baa"
Output : [ [ "b", "a", "a"] , [ "b", "aa" ] ]
Explanation : Above all are the possible ways in which the string can be partitioned so that each substring is a palindrome.
Input : s = "ab"
Imagine organizing a long sentence into meaningful phrases. Start at the beginning, find a segment that forms a meaningful phrase, and write it down. Move to the next segment and repeat the process. If reaching the end of the sentence and having a list of meaningful phrases, the job is done. If stuck, erase the last phrase, try a different segment, and continue until all segments are explored and every possible meaningful combination is found.
The process involves breaking down a problem into smaller sub-problems. Begin at the start of a string and identify palindromic substrings. Record a substring and proceed to the next part of the string. Continue this process until the end of the string. If the end is reached, a valid partition is found and stored. If a valid partition is not found, backtrack by removing the last recorded substring and try a different substring, exploring all possible palindromic partitions.
#include<bits/stdc++.h>
using namespace std;
class Solution {
public:
vector<vector<string>> partition(string s) {
// Resultant vector to store all partitions
vector<vector<string>> res;
// Temporary vector to store current partition
vector<string> path;
// Start the depth-first search from index 0
dfs(0, s, path, res);
return res;
}
void dfs(int index, string s, vector<string> &path, vector<vector<string>> &res) {
// If the index reaches the end of the string
if (index == s.size()) {
// Add the current partition to the result
res.push_back(path);
return;
}
// Iterate over the substring starting from 'index'
for (int i = index; i < s.size(); ++i) {
// Check if the substring s[index..i] is a palindrome
if (isPalindrome(s, index, i)) {
// If true, add it to the current path
path.push_back(s.substr(index, i - index + 1));
// Recur for the remaining substring
dfs(i + 1, s, path, res);
// Backtrack: remove the last added substring
path.pop_back();
}
}
}
bool isPalindrome(string s, int start, int end) {
// Check if the substring s[start..end] is a palindrome
while (start <= end) {
// If characters do not match, it's not a palindrome
if (s[start++] != s[end--])
return false;
}
return true; // Otherwise, it's a palindrome
}
};
// Main method for testing
int main() {
Solution solution;
string s = "aab";
vector<vector<string>> result = solution.partition(s);
for (const auto& partition : result) {
for (const auto& str : partition) {
cout << str << " ";
}
cout << endl;
}
return 0;
}
import java.util.ArrayList;
import java.util.List;
class Solution {
public List<List<String>> partition(String s) {
// Resultant list to store all partitions
List<List<String>> res = new ArrayList<>();
// Temporary list to store current partition
List<String> path = new ArrayList<>();
// Start the depth-first search from index 0
dfs(0, s, path, res);
return res;
}
private void dfs(int index, String s, List<String> path, List<List<String>> res) {
// If the index reaches the end of the string
if (index == s.length()) {
// Add the current partition to the result
res.add(new ArrayList<>(path));
return;
}
// Iterate over the substring starting from 'index'
for (int i = index; i < s.length(); i++) {
// Check if the substring s[index..i] is a palindrome
if (isPalindrome(s, index, i)) {
// If true, add it to the current path
path.add(s.substring(index, i + 1));
// Recur for the remaining substring
dfs(i + 1, s, path, res);
// Backtrack: remove the last added substring
path.remove(path.size() - 1);
}
}
}
private boolean isPalindrome(String s, int start, int end) {
// Check if the substring s[start..end] is a palindrome
while (start <= end) {
// If characters do not match, it's not a palindrome
if (s.charAt(start++) != s.charAt(end--))
return false;
}
return true; // Otherwise, it's a palindrome
}
// Main method for testing
public static void main(String[] args) {
Solution solution = new Solution();
String s = "aab";
List<List<String>> result = solution.partition(s);
for (List<String> partition : result) {
System.out.println(partition);
}
}
}
class Solution:
def partition(self, s: str):
def dfs(index, path):
# If index reaches the end of the string
if index == len(s):
# Add the current partition to the result
res.append(path[:])
return
# Iterate over the substring starting from 'index'
for i in range(index, len(s)):
# Check if the substring s[index..i] is a palindrome
if isPalindrome(index, i):
# If true, add it to the current path
path.append(s[index:i+1])
# Recur for the remaining substring
dfs(i+1, path)
# Backtrack: remove the last added substring
path.pop()
def isPalindrome(start, end):
# Check if the substring s[start..end] is a palindrome
while start <= end:
# If characters do not match, it's not a palindrome
if s[start] != s[end]:
return False
start += 1
end -= 1
return True # Otherwise, it's a palindrome
# Resultant list to store all partitions
res = []
# Start the depth-first search from index 0
dfs(0, [])
return res
# Main method for testing
if __name__ == "__main__":
solution = Solution()
s = "aab"
result = solution.partition(s)
for partition in result:
print(partition)
class Solution {
partition(s) {
// Resultant array to store all partitions
const res = [];
// Temporary array to store the current partition
const path = [];
// Start the depth-first search from index 0
this.dfs(0, s, path, res);
return res;
}
dfs(index, s, path, res) {
// If the index reaches the end of the string
if (index === s.length) {
// Add the current partition to the result
res.push([...path]);
return;
}
// Iterate over the substring starting from 'index'
for (let i = index; i < s.length; ++i) {
// Check if the substring s[index..i] is a palindrome
if (this.isPalindrome(s, index, i)) {
// If true, add it to the current path
path.push(s.substring(index, i + 1));
// Recur for the remaining substring
this.dfs(i + 1, s, path, res);
// Backtrack: remove the last added substring
path.pop();
}
}
}
isPalindrome(s, start, end) {
// Check if the substring s[start..end] is a palindrome
while (start <= end) {
// If characters do not match, it's not a palindrome
if (s[start++] !== s[end--]) {
return false;
}
}
return true; // Otherwise, it's a palindrome
}
}
// Main method for testing
const solution = new Solution();
const s = "aab";
const result = solution.partition(s);
result.forEach(partition => {
console.log(partition);
});
Time Complexity : The time complexity is O(2^N) due to the exponential number of possible partitions.
Space Complexity : The space complexity is O(N) for the recursion stack and additional space for storing partitions.
Q: How do you avoid duplicate partitions?
A: Duplicate partitions are naturally avoided because backtracking generates partitions by iterating through the string in order and only includes valid substrings.
Q: What if the input contains only palindromes?
A: The output will include all possible partitions, ranging from each character as a separate partition to the entire string as a single partition.
Q: What if the problem required finding only one valid partition?
A: Return the first partition found during backtracking. This reduces the search space and improves performance.
Q: What if overlapping palindromic substrings are allowed?
A: Modify the recursion to include overlapping substrings. This would require additional bookkeeping to avoid duplicate results.