questions F-L

This commit is contained in:
2025-05-25 11:47:04 +01:00
parent 798e0ba1df
commit 5dbe52df0d
54 changed files with 11235 additions and 0 deletions

View File

@@ -0,0 +1,171 @@
title: Longest Palindromic Substring
slug: longest-palindromic-substring
difficulty: medium
leetcode_id: 5
leetcode_url: https://leetcode.com/problems/longest-palindromic-substring/
categories:
- strings
- dynamic-programming
patterns:
- two-pointers
- dynamic-programming
description: |
Given a string `s`, return *the longest palindromic substring* in `s`.
A **palindrome** is a string that reads the same forward and backward.
constraints: |
- `1 <= s.length <= 1000`
- `s` consists of only digits and English letters
examples:
- input: 's = "babad"'
output: '"bab"'
explanation: '"aba" is also a valid answer — both have length 3.'
- input: 's = "cbbd"'
output: '"bb"'
explanation: "The longest palindromic substring is \"bb\" with length 2."
explanation:
intuition: |
Every palindrome has a **center**. For odd-length palindromes like "aba", the center is the middle character 'b'. For even-length palindromes like "abba", the center is the gap between the two 'b's.
Think of it like this: if we know the center, we can find the full palindrome by **expanding outward** — checking if the characters on both sides match. We keep expanding until they don't match.
The strategy is simple: try every possible center (each character and each gap between characters), expand to find the longest palindrome for that center, and track the overall longest.
This "expand around center" approach is intuitive and uses O(1) extra space, making it ideal for interviews.
approach: |
We solve this using **Expand Around Center**:
**Step 1: Define the expand helper function**
- `expand(left, right)` returns the bounds of the longest palindrome centered at this position
- While `left >= 0` and `right < len(s)` and `s[left] == s[right]`:
- Expand: decrement `left`, increment `right`
- Return the bounds of the palindrome (after adjusting for the last failed expansion)
&nbsp;
**Step 2: Try every possible center**
- For each index `i`:
- Try **odd-length** palindrome: `expand(i, i)` — center is single character
- Try **even-length** palindrome: `expand(i, i+1)` — center is between characters
- Update the best result if either expansion found a longer palindrome
&nbsp;
**Step 3: Return the longest palindrome**
- Track `start` and `end` indices of the best palindrome found
- Return `s[start:end+1]`
&nbsp;
Why does this work? By checking both odd and even centers at every position, we're guaranteed to find the center of the longest palindrome somewhere.
common_pitfalls:
- title: Forgetting Even-Length Palindromes
description: |
If you only expand around single characters, you'll miss even-length palindromes like "abba" or "bb".
Every position needs two expansion attempts: one for odd (center at `i`) and one for even (center between `i` and `i+1`).
wrong_approach: "Only calling expand(i, i)"
correct_approach: "Call both expand(i, i) and expand(i, i+1)"
- title: Index Out of Bounds During Expansion
description: |
The expansion loop must check bounds **before** accessing characters. A common mistake is checking equality first, which causes an index error.
wrong_approach: "while s[left] == s[right] and left >= 0 and right < len(s)"
correct_approach: "while left >= 0 and right < len(s) and s[left] == s[right]"
- title: Returning Length Instead of Substring
description: |
The problem asks for the actual substring, not just its length. Track the start and end positions of the best palindrome so you can extract it.
wrong_approach: "return max_length"
correct_approach: "return s[start:end+1]"
key_takeaways:
- "**Expand around center**: O(n²) time, O(1) space — optimal for interviews"
- "**Handle both odd and even**: Check single-character centers AND gaps between characters"
- "**Track positions, not just length**: You need to return the actual substring"
- "**Manacher's algorithm**: Can solve in O(n) but is complex — not expected in interviews"
time_complexity: "O(n²). For each of n possible centers, expansion can take up to O(n) time in the worst case."
space_complexity: "O(1). Only a few variables for tracking positions — no additional data structures."
solutions:
- approach_name: Expand Around Center
is_optimal: true
code: |
def longest_palindrome(s: str) -> str:
def expand(left: int, right: int) -> tuple[int, int]:
"""Expand around center and return palindrome bounds."""
while left >= 0 and right < len(s) and s[left] == s[right]:
left -= 1
right += 1
# Return bounds of palindrome (undo last expansion)
return left + 1, right - 1
start, end = 0, 0
for i in range(len(s)):
# Try odd-length palindrome (single character center)
l1, r1 = expand(i, i)
if r1 - l1 > end - start:
start, end = l1, r1
# Try even-length palindrome (center between characters)
l2, r2 = expand(i, i + 1)
if r2 - l2 > end - start:
start, end = l2, r2
return s[start:end + 1]
explanation: |
**Time Complexity:** O(n²) — n centers, up to n expansion steps each.
**Space Complexity:** O(1) — Only tracking start/end positions.
For each position, we try both odd and even palindrome centers. The expand function returns the bounds of the longest palindrome for that center. We track the overall longest and return it at the end.
- approach_name: Dynamic Programming
is_optimal: false
code: |
def longest_palindrome(s: str) -> str:
n = len(s)
if n < 2:
return s
# dp[i][j] = True if s[i:j+1] is a palindrome
dp = [[False] * n for _ in range(n)]
start, max_len = 0, 1
# Single characters are palindromes
for i in range(n):
dp[i][i] = True
# Check substrings of increasing length
for length in range(2, n + 1):
for i in range(n - length + 1):
j = i + length - 1
if length == 2:
# Two characters: palindrome if they match
dp[i][j] = s[i] == s[j]
else:
# Longer: palindrome if ends match AND inner is palindrome
dp[i][j] = s[i] == s[j] and dp[i + 1][j - 1]
if dp[i][j] and length > max_len:
start, max_len = i, length
return s[start:start + max_len]
explanation: |
**Time Complexity:** O(n²) — Fill n×n table.
**Space Complexity:** O(n²) — DP table storage.
Build up palindrome information from smaller to larger substrings. `dp[i][j]` is True if substring from i to j is a palindrome. A substring is a palindrome if its ends match and its inner substring is also a palindrome. Track the longest one found.