Palindrome Partitioning Using Backtracking in DSA Typescript - Time & Space Complexity
We want to understand how the time needed to find all palindrome partitions grows as the input string gets longer.
Specifically, how does the backtracking process scale with the size of the string?
Analyze the time complexity of the following code snippet.
function isPalindrome(s: string, start: number, end: number): boolean {
while (start < end) {
if (s.charAt(start) !== s.charAt(end)) return false;
start++;
end--;
}
return true;
}
function backtrack(s: string, start: number, path: string[], result: string[][]): void {
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();
}
}
}
This code finds all ways to split a string into palindrome parts using backtracking.
- Primary operation: The for-loop tries every possible substring start to end, and the recursive calls explore all partitions.
- How many times: The recursion explores many combinations, and palindrome checks happen for each substring considered.
As the string length grows, the number of possible palindrome partitions grows very fast.
| Input Size (n) | Approx. Operations |
|---|---|
| 3 | ~5 to 10 checks and recursive calls |
| 10 | Hundreds of palindrome checks and recursive calls |
| 15 | Thousands to tens of thousands of operations |
Pattern observation: The operations grow exponentially because each character can start a new palindrome or extend one, creating many combinations.
Time Complexity: O(n * 2^n)
This means the time needed grows very fast, roughly doubling with each added character, multiplied by the cost to check palindromes.
[X] Wrong: "The time complexity is just O(n^2) because of the nested loops."
[OK] Correct: The recursion explores many partitions, which leads to exponential growth, not just quadratic.
Understanding this complexity helps you explain how backtracking explores many possibilities and why pruning or memoization might be needed.
"What if we cached palindrome checks to avoid repeating them? 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 into palindrome parts.Final Answer:
To split a string into all possible palindrome substrings -> Option DQuick Check:
Palindrome partitioning = all palindrome splits [OK]
- Confusing palindrome partitioning with longest palindrome substring
- Thinking it only counts palindromes instead of listing partitions
- Assuming it just reverses the string
Solution
Step 1: Analyze parameter types
The string to partition is 's: string', start index is 'number', path is an array of strings, and result is an array of string arrays.Step 2: Check return type
Backtracking functions usually return void because they build results by modifying the result array.Final Answer:
function backtrack(s: string, start: number, path: string[], result: string[][]): void -> Option CQuick Check:
Correct signature = function backtrack(s: string, start: number, path: string[], result: string[][]): void [OK]
- Using wrong parameter types like number[] instead of string
- Returning boolean or number instead of void
- Passing path as string instead of string[]
"aab"?
function isPalindrome(s: string): boolean {
return s === s.split('').reverse().join('');
}
function backtrack(s: string, start: number, path: string[], result: string[][]): void {
if (start === s.length) {
result.push([...path]);
return;
}
for (let end = start + 1; end <= s.length; end++) {
const substr = s.substring(start, end);
if (isPalindrome(substr)) {
path.push(substr);
backtrack(s, end, path, result);
path.pop();
}
}
}
const result: string[][] = [];
backtrack("aab", 0, [], result);
console.log(result);Solution
Step 1: Identify palindrome substrings in "aab"
"a" and "aa" are palindromes; "b" is a palindrome; "ab" and "aab" are not.Step 2: Trace backtracking calls
Partitions found are ["a", "a", "b"] and ["aa", "b"] added to result.Final Answer:
[["a", "a", "b"], ["aa", "b"]] -> Option BQuick Check:
All palindrome splits of "aab" = [["a", "a", "b"], ["aa", "b"]] [OK]
- Including non-palindrome substrings like "ab"
- Missing the "aa" substring partition
- Returning only one partition instead of all
function isPalindrome(s: string): boolean {
return s === s.split('').reverse().join('');
}
function backtrack(s: string, start: number, path: string[], result: string[][]): void {
if (start > s.length) {
result.push([...path]);
return;
}
for (let end = start + 1; end <= s.length; end++) {
const substr = s.substring(start, end);
if (isPalindrome(substr)) {
path.push(substr);
backtrack(s, end, path, result);
path.pop();
}
}
}Solution
Step 1: Analyze base case condition
Condition 'start > s.length' allows start to be s.length + 1, which is invalid index.Step 2: Correct base case for recursion end
It should be 'start === s.length' to indicate full string processed and add path to result.Final Answer:
Change condition to if (start === s.length) to stop recursion correctly -> Option AQuick Check:
Base case must be start === s.length [OK]
- Using > instead of === in base case
- Removing path.pop() causing wrong partitions
- Changing substring method unnecessarily
"racecar", which of the following is NOT a valid palindrome partitioning produced by a backtracking algorithm?Solution
Step 1: Check palindrome validity of each substring
"rac" and "ecar" are not palindromes; others are single letters or full palindrome.Step 2: Confirm valid partitions
Partitions with only palindrome substrings are valid; those with non-palindromes are invalid.Final Answer:
["rac", "ecar"] -> Option AQuick Check:
Non-palindrome substrings invalidate partition [OK]
- Assuming any split is valid without palindrome check
- Confusing full string palindrome with partial substrings
- Ignoring single character substrings as palindromes
Ready to prove it?
Pass the test and this pattern moves unknown
