Palindrome Partitioning Using Backtracking in DSA Javascript - Time & Space Complexity
We want to understand how the time needed grows when we find all palindrome partitions of a string using backtracking.
How does the number of steps change as the string gets longer?
Analyze the time complexity of the following code snippet.
function isPalindrome(s, start, end) {
while (start < end) {
if (s[start] !== s[end]) return false;
start++;
end--;
}
return true;
}
function backtrack(s, start, path, result) {
if (start === s.length) {
result.push([...path]);
return;
}
for (let end = start; end < s.length; end++) {
if (isPalindrome(s, start, end)) {
path.push(s.substring(start, end + 1));
backtrack(s, end + 1, path, result);
path.pop();
}
}
}
function partition(s) {
const result = [];
backtrack(s, 0, [], result);
return result;
}
This code finds all ways to split a string into parts where each part is a palindrome, using backtracking.
Identify the loops, recursion, array traversals that repeat.
- Primary operation: The recursive backtracking explores all substring partitions, checking palindromes repeatedly.
- How many times: For each position, it tries all possible substring ends, and for each substring, it checks palindrome by scanning characters.
As the string length grows, the number of palindrome partitions grows very fast, and palindrome checks happen many times.
| Input Size (n) | Approx. Operations |
|---|---|
| 10 | Thousands of palindrome checks and recursive calls |
| 100 | Millions to billions of operations due to many partitions |
| 1000 | Operations explode exponentially, not practical without optimization |
Pattern observation: The work grows exponentially because every substring can lead to multiple recursive paths.
Time Complexity: O(n * 2^n)
This means the time grows roughly like two to the power of the string length times the length itself, because we explore many partitions and check palindromes.
[X] Wrong: "The time complexity is just O(n^2) because we only check substrings."
[OK] Correct: The number of possible partitions grows exponentially, so the recursive calls multiply quickly beyond just substring checks.
Understanding this complexity helps you explain why backtracking can be slow and when to expect exponential time, a key skill for problem solving.
"What if we cached palindrome checks to avoid repeated work? How would the time complexity change?"
Practice
Solution
Step 1: Understand palindrome partitioning
Palindrome partitioning means dividing a string into parts where each part is a palindrome.Step 2: Role of backtracking
Backtracking helps explore all possible ways to split the string and keep only palindrome parts.Final Answer:
To split a string into all possible palindrome substrings -> Option AQuick Check:
Palindrome partitioning = splitting into palindrome substrings [OK]
- Confusing palindrome partitioning with longest palindrome substring
- Thinking it only finds one palindrome partition
- Assuming it reverses the string
s.slice(start, end) is a palindrome in JavaScript?Solution
Step 1: Extract substring correctly
Uses.slice(start, end)to get substring from start to end-1.Step 2: Check palindrome by reversing substring
Reverse substring by splitting to array, reversing, then joining back to string.Final Answer:
Check if s.slice(start, end) === s.slice(start, end).split('').reverse().join('') -> Option BQuick Check:
Reverse substring and compare equals original [OK]
- Using slice with reversed indices (end before start)
- Trying to reverse string directly without split
- Comparing substring to reversed full string
function isPalindrome(s) {
return s === s.split('').reverse().join('');
}
function backtrack(s, start, path, result) {
if (start === s.length) {
result.push([...path]);
return;
}
for (let end = start + 1; end <= s.length; end++) {
let sub = s.slice(start, end);
if (isPalindrome(sub)) {
path.push(sub);
backtrack(s, end, path, result);
path.pop();
}
}
}
let result = [];
backtrack('aab', 0, [], result);
console.log(result);Solution
Step 1: Check palindrome substrings in 'aab'
Substrings: 'a', 'aa', 'aab', 'ab', 'b'. Palindromes are 'a', 'aa', 'b'.Step 2: Backtracking builds partitions
Partitions: ['a','a','b'] and ['aa','b'] are valid palindrome partitions.Final Answer:
[["a", "a", "b"], ["aa", "b"]] -> Option AQuick Check:
All palindrome partitions of 'aab' = [['a','a','b'], ['aa','b']] [OK]
- Including non-palindrome substrings like 'ab'
- Missing the partition ['aa','b']
- Confusing output format with strings instead of arrays
function backtrack(s, start, path, result) {
if (start > s.length) {
result.push(path);
return;
}
for (let end = start + 1; end <= s.length; end++) {
let sub = s.slice(start, end);
if (sub === sub.split('').reverse().join('')) {
path.push(sub);
backtrack(s, end, path, result);
path.pop();
}
}
}Solution
Step 1: Analyze base case condition
Base case triggers when start > s.length, but valid partitions end exactly at start === s.length.Step 2: Correct base case to push result
Change condition to start === s.length to add current path to result correctly.Final Answer:
The base case condition should be start === s.length, not start > s.length -> Option CQuick Check:
Base case triggers at string end index [OK]
- Using > instead of === for base case
- Not pushing a copy of path (but not asked here)
- Starting loop incorrectly at start instead of start+1
"racecar", how many palindrome partitions will the backtracking algorithm find?Solution
Step 1: Identify palindrome substrings in 'racecar'
Palindromes include all single characters 'r','a','c','e','c','a','r'; 'cec' (indices 2-4); 'aceca' (1-5); 'racecar' (whole).Step 2: Count all palindrome partitions
Valid partitions: ['racecar'], ['r','aceca','r'], ['r','a','cec','a','r'], ['r','a','c','e','c','a','r'], and others. Total 10.Final Answer:
10 -> Option DQuick Check:
Backtracking finds 10 palindrome partitions for 'racecar' [OK]
- Counting only single-character partitions
- Missing larger palindrome substrings like 'aceca'
- Assuming only 1 or 2 partitions exist
Ready to prove it?
Pass the test and this pattern moves unknown
