-
Notifications
You must be signed in to change notification settings - Fork 273
The Longest Mirror
TIP103 Unit 12 Session 1 (Click for link to problem statements)
Given a string s, find the longest contiguous stretch that reads the same forwards and backwards.
Return that longest palindromic substring; if more than one has the maximum length, any of them is acceptable.
def longest_palindrome(s):
pass- 💡 Difficulty: Medium
- ⏰ Time to complete: 25-30 mins
- 🛠️ Topics: Strings, Palindromes, Two Pointers, Expand Around Center
Understand what the interviewer is asking for by using test cases and questions about the problem.
- Established a set (2-3) of test cases to verify their own solution later.
- Established a set (1-2) of edge cases to verify their solution handles complexities.
- Have fully understood the problem and have no clarifying questions.
- Have you verified any Time/Space Constraints for this problem?
-
Q: What counts as a "mirror" here?
- A: A contiguous substring that is a palindrome — reversing it produces the same string, e.g.
"bab"or"bb". It must be consecutive characters (a substring), not a subsequence.
- A: A contiguous substring that is a palindrome — reversing it produces the same string, e.g.
-
Q: What should we return if several palindromic substrings tie for the maximum length?
- A: Any one of them is acceptable. For
"babad", both"bab"and"aba"are valid answers.
- A: Any one of them is acceptable. For
-
Q: Do we need to consider even-length palindromes as well as odd-length ones?
- A: Yes.
"bb"in"cbbd"is an even-length palindrome, so both kinds of centers must be checked.
- A: Yes.
HAPPY CASE
Input: s = "babad"
Output: "bab"
Explanation: "bab" is a palindrome of length 3, the longest in the string. ("aba" would also be accepted.)
Input: s = "cbbd"
Output: "bb"
Explanation: The longest mirror here has even length; "bb" reads the same in both directions.
EDGE CASE
Input: s = "abc"
Output: "a"
Explanation: No two adjacent characters match, so the longest palindrome is any single character.
Input: s = "racecar"
Output: "racecar"
Explanation: The entire string is a palindrome, so the whole string is returned.
Match what this problem looks like to known categories of problems, e.g. Linked List or Dynamic Programming, and strategies or patterns in those categories.
For Palindrome / Substring Problems, we can consider the following approaches:
-
Expand Around Center (Two Pointers): Every palindrome is symmetric about a center. Try each of the
2N - 1possible centers (each character for odd lengths, each gap between adjacent characters for even lengths) and grow two pointers outward while the characters mirror each other. -
Dynamic Programming: A table
dp[i][j]can record whethers[i..j]is a palindrome, but it costsO(N^2)space, whereas expanding around centers achieves the sameO(N^2)time in constant space. -
Brute Force: Checking every substring for being a palindrome is
O(N^3)— too slow for anything but tiny inputs.
Plan the solution with appropriate visualizations and pseudocode.
General Idea:
Treat each index as the potential center of a palindrome. From every center, use two pointers to expand outward while the left and right characters match. Track the bounds of the longest palindrome seen so far, checking both an odd-length center (a single character) and an even-length center (a pair of adjacent characters) at each position.
1) If the string is empty, return "".
2) Track `start` and `end`, the bounds of the best palindrome found so far.
3) Define a helper expand(left, right):
a) While left and right are in bounds and s[left] == s[right], move left one step left and right one step right.
b) The loop overshoots by one on each side, so return (left + 1, right - 1).
4) For each index i in the string:
a) Expand around the odd center (i, i); if the result is longer, update start/end.
b) Expand around the even center (i, i+1); if the result is longer, update start/end.
5) Return the slice s[start..end].
- Only checking odd-length centers
(i, i)and missing even-length palindromes like"bb"in"cbbd". - Forgetting that the expansion loop stops one step past the palindrome on each side, and returning the wrong bounds.
- Building a new substring on every expansion instead of tracking indices, which does extra copying work.
- Returning the length of the palindrome instead of the palindrome itself.
Implement the code to solve the algorithm.
def longest_palindrome(s):
if not s:
return ""
start, end = 0, 0 # Bounds of the best palindrome found so far
def expand(left, right):
# Grow outward while the characters mirror each other
while left >= 0 and right < len(s) and s[left] == s[right]:
left -= 1
right += 1
# The loop overshoots by one on each side
return left + 1, right - 1
for i in range(len(s)):
# Odd-length palindrome centered at index i
l1, r1 = expand(i, i)
if r1 - l1 > end - start:
start, end = l1, r1
# Even-length palindrome centered between i and i+1
l2, r2 = expand(i, i + 1)
if r2 - l2 > end - start:
start, end = l2, r2
return s[start:end + 1]Review the code by running specific example(s) and recording values (watchlist) of your code's variables along the way.
-
Input: s = "babad"
- Center i = 0 (
'b'): odd expansion yields only"b"; best bounds stay (0, 0). - Center i = 1 (
'a'): odd expansion matchess[0] == s[2]('b' == 'b'), then stops at the left boundary, yielding"bab"; best bounds become (0, 2). - Center i = 2 (
'b'): odd expansion yields"aba", also length 3, so the bounds are not updated. - Remaining centers find nothing longer, and no even center ever matches.
- Output: "bab"
- Center i = 0 (
-
Input: s = "cbbd"
- Odd centers each yield only single characters.
- Even center i = 1 (
s[1]ands[2]):'b' == 'b', expansion stops when'c' != 'd', yielding"bb"; best bounds become (1, 2). - Output: "bb"
-
Input: s = "racecar"
- Center i = 3 (
'e'): expansion matches all the way out to both ends of the string. - Output: "racecar" (the entire string is a palindrome).
- Center i = 3 (
Evaluate the performance of your algorithm and state any strong/weak or future potential work.
Assume N is the length of the string s.
-
Time Complexity:
O(N^2)because there are2N - 1centers and each expansion can extend up toO(N)steps outward. -
Space Complexity:
O(1)extra space, since we only track indices; the final slice for the answer isO(N), the size of the output itself.