Palindrome Partitioning Using Backtracking in DSA Python - 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 string size?
Analyze the time complexity of the following code snippet.
def is_palindrome(s, start, end):
while start < end:
if s[start] != s[end]:
return False
start += 1
end -= 1
return True
def backtrack(s, start, path, result):
if start == len(s):
result.append(path[:])
return
for end in range(start, len(s)):
if is_palindrome(s, start, end):
path.append(s[start:end+1])
backtrack(s, end+1, path, result)
path.pop()
This code finds all ways to split the string into palindrome parts using backtracking.
Identify the loops, recursion, array traversals that repeat.
- Primary operation: The recursive backtracking explores all substring partitions, checking each substring for palindrome.
- How many times: The recursion can branch many times, exploring many substring splits; palindrome checks happen for each substring considered.
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 operations grow faster than any simple polynomial, roughly exponentially with input size.
Time Complexity: O(n * 2^n)
This means the time grows very fast as the string gets longer, because we explore many partitions and check palindromes for each.
[X] Wrong: "The algorithm runs in polynomial time because it just uses loops and recursion."
[OK] Correct: The number of partitions grows exponentially, so the recursion explores an exponential number of paths, not just polynomial.
Understanding this complexity helps you explain why backtracking can be expensive and when to expect exponential time, which is valuable for problem-solving discussions.
"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 splits and keeps only those where every substring is a palindrome.Final Answer:
To split s into all possible substrings where each substring is a palindrome -> Option AQuick Check:
Palindrome partitioning = all palindrome substrings [OK]
- Confusing palindrome partitioning with longest palindrome substring
- Thinking it counts palindromes instead of listing partitions
- Assuming it just reverses the string
s[i:j] is a palindrome inside a backtracking function?Solution
Step 1: Understand Python slicing and reversal
Usings[i:j][::-1]reverses the substring from index i to j-1.Step 2: Compare substring with its reverse
Ifs[i:j]equals its reversed version, it is a palindrome.Final Answer:
if s[i:j] == s[i:j][::-1]: -> Option CQuick Check:
Substring == reversed substring [OK]
- Using reversed() which returns an iterator, not a string
- Comparing s[i:j] with s[j:i] which is empty or invalid
- Incorrect slicing order causing empty strings
def backtrack(s, start, path, result):
if start == len(s):
result.append(path[:])
return
for end in range(start + 1, len(s) + 1):
if s[start:end] == s[start:end][::-1]:
path.append(s[start:end])
backtrack(s, end, path, result)
path.pop()
result = []
backtrack('aab', 0, [], result)
print(result)Solution
Step 1: Trace backtracking on 'aab'
Partitions found are ['a','a','b'] and ['aa','b'] because 'a', 'aa', and 'b' are palindromes.Step 2: Confirm all palindrome partitions collected
Both partitions are added to result list before printing.Final Answer:
[['a', 'a', 'b'], ['aa', 'b']] -> Option AQuick Check:
All palindrome partitions = [['a', 'a', 'b'], ['aa', 'b']] [OK]
- Missing the partition ['aa', 'b']
- Including non-palindrome substrings like 'ab'
- Not popping path after recursion causing wrong results
def backtrack(s, start, path, result):
if start == len(s):
result.append(path)
return
for end in range(start + 1, len(s) + 1):
if s[start:end] == s[start:end][::-1]:
path.append(s[start:end])
backtrack(s, end, path, result)
path.pop()
result = []
backtrack('aba', 0, [], result)
print(result)Solution
Step 1: Understand list reference behavior in Python
Appendingpathdirectly adds a reference, so all entries point to the same list.Step 2: Fix by appending a copy of path
Useresult.append(path[:])to save a snapshot of current path.Final Answer:
Appending path directly causes all results to be the same list -> Option DQuick Check:
Append copy of path, not path itself [OK]
- Appending the same list reference causing duplicate results
- Incorrect palindrome check logic
- Wrong loop range causing missed substrings
s = 'racecar', how many unique palindrome partitions will the backtracking algorithm find?Solution
Step 1: List all palindrome partitions of 'racecar'
Partitions include: ['r', 'a', 'c', 'e', 'c', 'a', 'r'], ['r', 'a', 'cec', 'a', 'r'], ['r', 'aceca', 'r'], ['racecar'], ['r', 'aceca', 'r'], ['r', 'a', 'c', 'e', 'c', 'a', 'r'], ['r', 'a', 'cec', 'a', 'r'], and others totaling 8 unique partitions.Step 2: Confirm count by backtracking logic
Backtracking finds all palindrome splits, totaling 8 unique partitions.Final Answer:
8 -> Option BQuick Check:
Unique palindrome partitions count = 8 [OK]
- Counting non-palindrome substrings as partitions
- Missing longer palindrome substrings like 'aceca'
- Assuming only single-character partitions
Ready to prove it?
Pass the test and this pattern moves unknown
