Expand around center index 2: left=2, right=2. Characters match ('c' == 'c'), count increments to 3.
💡 Single character palindrome found at last index.
Line:expand(i, i) # i=2
💡 Counting all single character palindromes.
expand
Attempt to expand odd-length palindrome at center 2 further
Expand left=1, right=3, but right is out of bounds, stop expansion.
💡 Expansion stops at string boundary.
Line:while left >= 0 and right < n and s[left] == s[right]: ...
💡 Boundaries limit palindrome expansion.
expand
Start even-length expansion at center between 2 and 3
Expand around center between indices 2 and 3: right index 3 is out of bounds, no palindrome found.
💡 Even-length expansions require valid right index.
Line:expand(i, i + 1) # i=2
💡 No palindrome possible beyond string end.
reconstruct
Return total palindrome count
All expansions done, return the total count of palindromic substrings found: 3.
💡 Final count reflects all palindromes found by expansions.
Line:return count
💡 The algorithm successfully counted all palindromic substrings.
def countSubstrings(s: str) -> int:
n = len(s) # STEP 1
count = 0 # STEP 1
def expand(left, right):
nonlocal count
while left >= 0 and right < n and s[left] == s[right]: # STEP 2-10
count += 1 # STEP 2,5,8
left -= 1 # STEP 3,6,9
right += 1 # STEP 3,6,9
for i in range(n): # STEP 2,4,5,7,8,10
expand(i, i) # Odd length palindromes
expand(i, i + 1) # Even length palindromes
return count # STEP 11
if __name__ == '__main__':
print(countSubstrings('abc')) # Expected output: 3
📊
Count Palindromic Substrings - Watch the Algorithm Execute, Step by Step
Watching the expansion around centers visually reveals how palindromes grow and overlap, making the counting process intuitive and clear.
Step 1/11
·Active fill★Answer cell
Initializing dp array
i\w
0
1
2
i=0
?
?
?
i=1
?
?
?
i=2
?
?
?
Item 0 - wt:1 val:1
i\w
0
1
2
i=0
1
?
?
i=1
?
?
?
i=2
?
?
?
palindrome found
Item 0 - wt:1 val:1
i\w
0
1
2
i=0
1
?
?
i=1
?
?
?
i=2
?
?
?
palindrome confirmed
Item 0 - wt:0 val:1
i\w
0
1
2
i=0
1
?
?
i=1
?
?
?
i=2
?
?
?
no palindrome
Item 1 - wt:1 val:2
i\w
0
1
2
i=0
1
?
?
i=1
?
1
?
i=2
?
?
?
palindrome found
Item 1 - wt:0 val:2
i\w
0
1
2
i=0
1
?
?
i=1
?
1
?
i=2
?
?
?
no palindrome
Item 1 - wt:0 val:2
i\w
0
1
2
i=0
1
?
?
i=1
?
1
?
i=2
?
?
?
no palindrome
Item 2 - wt:1 val:3
i\w
0
1
2
i=0
1
?
?
i=1
?
1
?
i=2
?
?
1
palindrome found
Item 2 - wt:0 val:3
i\w
0
1
2
i=0
1
?
?
i=1
?
1
?
i=2
?
?
1
Item 2 - wt:0 val:3
i\w
0
1
2
i=0
1
?
?
i=1
?
1
?
i=2
?
?
1
Initializing dp array
i\w
0
1
2
i=0
1
?
?
i=1
?
1
?
i=2
?
?
1
palindrome
Key Takeaways
✓ Every single character in the string is a palindrome by itself.
This is the base case that the algorithm counts first before expanding.
✓ Palindrome expansions stop immediately when characters at the expanding pointers differ or boundaries are exceeded.
This shows how the algorithm efficiently avoids unnecessary checks.
✓ Even-length palindromes require two adjacent matching characters as a center, which may not always exist.
This explains why some expansions yield zero palindromes and helps understand the difference between odd and even expansions.
Practice
(1/5)
1. What is the time complexity of the dynamic programming solution for the longest palindromic substring problem, and why?
medium
A. O(n^2) because the DP table of size nxn is filled once
B. O(n) because each character is processed once
C. O(n^3) because each substring is checked with a nested loop and palindrome check
D. O(n^2) but with extra O(n) recursion stack space
Solution
Step 1: Identify loops in DP solution
Two nested loops: outer over substring length (up to n), inner over start index (up to n), total O(n^2).
Step 2: Confirm no extra recursion or nested palindrome checks
Palindrome check is O(1) via DP table lookup, no recursion stack used.
Final Answer:
Option A -> Option A
Quick Check:
DP table size nxn filled once -> O(n^2) time [OK]
Hint: DP fills nxn table once, no recursion [OK]
Common Mistakes:
Confusing brute force O(n^3) with DP
Assuming recursion stack adds O(n) space
Thinking each substring palindrome check is O(n)
2. The following code attempts to find the longest palindromic substring using DP. Identify the line containing the subtle bug that causes incorrect results for some inputs.
medium
A. Line: if length < 3:
B. Line: dp[i][i] = True
C. Line: dp[i][j] = dp[i + 1][j - 1]
D. Line: for i in range(n - length + 1):
Solution
Step 1: Compare condition with correct code
The correct condition is length <= 3, but here it is length < 3, so length=3 substrings are not handled correctly.
Step 2: Understand impact
For length=3, dp[i][j] should be True if s[i]==s[j], but this code skips that, causing missed palindromes of length 3.
Final Answer:
Option A -> Option A
Quick Check:
Changing < to <= fixes the bug [OK]
Hint: Check boundary conditions for length 3 palindromes [OK]
Common Mistakes:
Off-by-one in length condition
Confusing substring indices
Incorrect DP table initialization
3. Suppose you want to count the number of distinct subsequences of t in s, but now characters in s can be reused multiple times (i.e., you can use the same character in s multiple times to form subsequences). Which modification to the DP approach correctly solves this variant?
hard
A. Use a 2D DP where dp[i][j] counts subsequences using first i chars of s and j chars of t, but allow reusing s[i] by not incrementing i on match
B. Change the recurrence to allow staying at the same i index when matching characters
C. Use the same DP but iterate j forward instead of backward in the inner loop
D. No change needed; original DP already counts subsequences with reuse
Solution
Step 1: Understand reuse means characters in s can be used multiple times
Original DP assumes each character in s can be used at most once per subsequence.
Step 2: Modify DP to allow reusing s[i]
Use 2D DP where dp[i][j] counts subsequences using first i chars of s for first j chars of t, and when s[i] matches t[j], allow staying at i (not incrementing) to reuse character.
Step 3: Recognize that iterating j forward or no change won't handle reuse correctly
Only explicit state allowing reuse by not advancing i on match works.
Final Answer:
Option A -> Option A
Quick Check:
Allowing reuse requires 2D DP with careful state transitions [OK]
Hint: Reuse means allowing same s[i] multiple times, so must not always increment i
Common Mistakes:
Assuming original DP handles reuse
Trying to fix by changing iteration order only
4. Suppose you want to find the longest palindromic subsequence in a string where characters can be reused unlimited times. Which modification to the DP approach correctly handles this variant?
hard
A. Modify DP to consider infinite reuse by allowing i to stay fixed while j moves, and vice versa
B. Use a greedy approach selecting matching characters repeatedly from both ends
C. Use the same DP but allow indices i and j to move independently without restriction
D. This problem reduces to longest palindromic substring, so use Manacher's algorithm
Solution
Step 1: Understand reuse means characters can be counted multiple times
Standard LPS counts each character once; reuse requires relaxing index movement constraints.
Step 2: Modify DP transitions to allow staying at i or j to reuse characters
DP must consider cases where i or j does not advance to reuse characters, effectively allowing repeated use.
Final Answer:
Option A -> Option A
Quick Check:
Allowing indices to stay or move independently models reuse correctly [OK]
Hint: Reuse means relaxing index movement in DP transitions [OK]
Common Mistakes:
Using greedy approach
Confusing substring with subsequence
Applying substring algorithms incorrectly
5. Suppose the wildcard pattern matching problem is extended so that the '*' wildcard can match any sequence of characters, but now the input string can be infinitely long (streaming input). Which modification to the DP approach is necessary to handle this scenario efficiently?
hard
A. Switch to a greedy two-pointer approach that backtracks on '*' positions to avoid DP overhead
B. Use recursion with memoization caching all substring pairs to handle infinite input
C. Precompute all possible matches for '*' in advance and store in a lookup table
D. Use the same space-optimized DP with arrays sized by pattern length, processing input character by character
Solution
Step 1: Understand infinite input constraints
DP requires O(m*n) time and space, not feasible for infinite input length.
Step 2: Identify suitable approach
Greedy two-pointer with backtracking on '*' positions can process streaming input efficiently without full DP table.
Step 3: Why other options fail
Precomputing or recursion with memoization is impossible with infinite input; DP arrays cannot grow infinitely.
Final Answer:
Option A -> Option A
Quick Check:
Greedy with backtracking handles streaming input efficiently [OK]
Hint: Infinite input forbids DP; greedy with backtracking is needed [OK]
Common Mistakes:
Trying DP on infinite input
Assuming memoization works with infinite data
Ignoring streaming constraints
Recommended
Ready to prove it?
Pass the test and this pattern moves unknownstrongwhile earning +1 Grip toward your certificate.