Palindrome Partitioning Using Backtracking in DSA C++ - Time & Space Complexity
We want to understand how the time needed to find all palindrome partitions grows as the input string gets longer.
How does the number of steps change when the string size increases?
Analyze the time complexity of the following code snippet.
bool isPalindrome(const string &s, int start, int end) {
while (start < end) {
if (s[start++] != s[end--]) return false;
}
return true;
}
void backtrack(int start, const string &s, vector ¤t, vector> &result) {
if (start == s.size()) {
result.push_back(current);
return;
}
for (int end = start; end < s.size(); ++end) {
if (isPalindrome(s, start, end)) {
current.push_back(s.substr(start, end - start + 1));
backtrack(end + 1, s, current, result);
current.pop_back();
}
}
}
This code finds all ways to split a string into palindrome parts using backtracking.
Identify the loops, recursion, array traversals that repeat.
- Primary operation: The for-loop tries every possible substring start to end, and the recursive call explores partitions from there.
- How many times: The recursion explores all possible partitions, which can be very large, and each palindrome check scans part of the substring.
As the string length grows, the number of possible partitions grows very fast, and each partition requires palindrome checks.
| Input Size (n) | Approx. Operations |
|---|---|
| 10 | Thousands of checks and recursive calls |
| 100 | Millions to billions of operations |
| 1000 | Operations grow beyond practical limits |
Pattern observation: The number of partitions grows exponentially, so the time grows very quickly as n increases.
Time Complexity: O(n * 2^n)
This means the time needed grows roughly like 2 to the power of the string length times the length itself, because we explore many partitions and check palindromes.
[X] Wrong: "The algorithm runs in polynomial time because it just uses loops and recursion."
[OK] Correct: The number of possible palindrome partitions grows exponentially, so the recursion explores an exponential number of cases, not just polynomial.
Understanding this complexity helps you explain why backtracking can be slow and when to expect exponential time, which is a valuable skill in problem solving.
"What if we used memoization to store palindrome checks? How would the time complexity change?"
Practice
s?Solution
Step 1: Understand palindrome partitioning
Palindrome partitioning means dividing the string into parts where each part reads the same forwards and backwards.Step 2: Role of backtracking
Backtracking tries all possible partitions and keeps only those where every substring is a palindrome.Final Answer:
To splitsinto substrings where each substring is a palindrome -> Option AQuick Check:
Palindrome partitioning = splitting into palindrome substrings [OK]
- Confusing palindrome partitioning with finding longest palindrome
- Thinking it counts palindromes instead of partitioning
- Assuming it reverses the string
s starting at index start?Solution
Step 1: Understand base case in backtracking
The base case occurs when the start index reaches the end of the string, meaning a full partition is formed.Step 2: What to do at base case
At this point, the current partition is a valid palindrome partition and should be added to the result list.Final Answer:
if (start == s.length()) add current partition to result; -> Option AQuick Check:
Base case adds partition when start reaches string end [OK]
- Returning true/false instead of adding partition
- Checking start > length instead of == length
- Using invalid index checks like start < 0
void backtrack(string s, int start, vector<string>& path, vector& res) {
if (start == s.size()) {
res.push_back(path);
return;
}
for (int end = start; end < s.size(); ++end) {
string sub = s.substr(start, end - start + 1);
string rev = sub;
reverse(rev.begin(), rev.end());
if (sub == rev) {
path.push_back(sub);
backtrack(s, end + 1, path, res);
path.pop_back();
}
}
}
int main() {
string s = "aab";
vector res;
vector<string> path;
backtrack(s, 0, path, res);
for (auto &v : res) {
for (auto &str : v) cout << str << " ";
cout << endl;
}
return 0;
}Solution
Step 1: Trace palindrome partitions of "aab"
Possible palindrome partitions are ["a", "a", "b"] and ["aa", "b"].Step 2: Check output format
The code prints each partition on a new line with substrings separated by spaces, so output lines are "a a b" and "aa b".Final Answer:
a a b \naa b -> Option CQuick Check:
Partitions = ["a","a","b"], ["aa","b"] [OK]
- Missing the "aa" substring partition
- Printing partitions in wrong order
- Confusing substring boundaries
void backtrack(string s, int start, vector<string>& path, vector& res) {
if (start == s.size()) {
res.push_back(path);
return;
}
for (int end = start; end < s.size(); ++end) {
string sub = s.substr(start, end - start + 1);
if (isPalindrome(sub)) {
path.push_back(sub);
backtrack(s, end, path, res); // Bug here
path.pop_back();
}
}
}Solution
Step 1: Analyze recursive call index
The recursive call usesendas the next start index, but it should move past the current substring.Step 2: Correct index to avoid infinite loop
Usingend + 1ensures the next substring starts after the current one, preventing repeated processing.Final Answer:
The recursive call should use end + 1 instead of end -> Option BQuick Check:
Next start index = end + 1 to avoid overlap [OK]
- Using end instead of end + 1 causes infinite recursion
- Ignoring base case correctness
- Assuming substring extraction is wrong
s = "racecarannakayak", how many palindrome partitions can be formed using backtracking? (Assume all partitions are valid palindrome splits.)Solution
Step 1: Identify palindromic substrings in
Substrings like "racecar", "anna", "kayak" are palindromes. Smaller palindromes like "a", "c", "r" also exist.sStep 2: Count partitions using backtracking
Backtracking explores all splits where each substring is palindrome. For this string, there are 8 valid partitions combining these palindromes.Final Answer:
8 -> Option DQuick Check:
Backtracking counts 8 palindrome partitions for given string [OK]
- Counting only large palindromes
- Missing smaller palindrome partitions
- Assuming fewer partitions than actual
Ready to prove it?
Pass the test and this pattern moves unknown
