Welcome to Subscribe On Youtube
647. Palindromic Substrings
Description
Given a string s, return the number of palindromic substrings in it.
A string is a palindrome when it reads the same backward as forward.
A substring is a contiguous sequence of characters within the string.
Example 1:
Input: s = "abc" Output: 3 Explanation: Three palindromic strings: "a", "b", "c".
Example 2:
Input: s = "aaa" Output: 6 Explanation: Six palindromic strings: "a", "a", "a", "aa", "aa", "aaa".
Constraints:
1 <= s.length <= 1000sconsists of lowercase English letters.
Solutions
Solution 1: Expand Around Center
We can enumerate the center position of each palindrome and expand outward to count the number of palindromic substrings. For a string of length $n$, there are $2n-1$ possible center positions (covering both odd-length and even-length palindromes). For each center, we expand outward until the palindrome condition is no longer satisfied, and count the number of palindromic substrings.
The time complexity is $O(n^2)$, where $n$ is the length of string $s$. The space complexity is $O(1)$.
Solution 2: Manacher’s Algorithm
In Manacher’s algorithm, $p[i] - 1$ represents the maximum palindrome length centered at position $i$, and the number of palindromic substrings centered at position $i$ is $\left \lceil \frac{p[i]-1}{2} \right \rceil$.
The time complexity is $O(n)$ and the space complexity is $O(n)$, where $n$ is the length of string $s$.
-
class Solution { public int countSubstrings(String s) { StringBuilder sb = new StringBuilder("^#"); for (char ch : s.toCharArray()) { sb.append(ch).append('#'); } String t = sb.append('$').toString(); int n = t.length(); int[] p = new int[n]; int pos = 0, maxRight = 0; int ans = 0; for (int i = 1; i < n - 1; i++) { p[i] = maxRight > i ? Math.min(maxRight - i, p[2 * pos - i]) : 1; while (t.charAt(i - p[i]) == t.charAt(i + p[i])) { p[i]++; } if (i + p[i] > maxRight) { maxRight = i + p[i]; pos = i; } ans += p[i] / 2; } return ans; } } // Solution 2 class Solution { public int countSubstrings(String s) { StringBuilder sb = new StringBuilder("^#"); for (char ch : s.toCharArray()) { sb.append(ch).append('#'); } String t = sb.append('$').toString(); int n = t.length(); int[] p = new int[n]; int pos = 0, maxRight = 0; int ans = 0; for (int i = 1; i < n - 1; i++) { p[i] = maxRight > i ? Math.min(maxRight - i, p[2 * pos - i]) : 1; while (t.charAt(i - p[i]) == t.charAt(i + p[i])) { p[i]++; } if (i + p[i] > maxRight) { maxRight = i + p[i]; pos = i; } ans += p[i] / 2; } return ans; } } -
class Solution { public: int countSubstrings(string s) { int ans = 0; int n = s.size(); for (int k = 0; k < n * 2 - 1; ++k) { int i = k / 2, j = (k + 1) / 2; while (~i && j < n && s[i] == s[j]) { ++ans; --i; ++j; } } return ans; } }; // Solution 2 class Solution { public: int countSubstrings(string s) { string t = "^#"; for (char c : s) { t += c; t += '#'; } t += "$"; int n = t.size(); vector<int> p(n, 0); int pos = 0, maxRight = 0; int ans = 0; for (int i = 1; i < n - 1; ++i) { if (maxRight > i) { p[i] = min(maxRight - i, p[2 * pos - i]); } else { p[i] = 1; } while (t[i - p[i]] == t[i + p[i]]) { ++p[i]; } if (i + p[i] > maxRight) { maxRight = i + p[i]; pos = i; } ans += p[i] / 2; } return ans; } }; -
class Solution: def countSubstrings(self, s: str) -> int: t = '^#' + '#'.join(s) + '#$' n = len(t) p = [0 for _ in range(n)] pos, maxRight = 0, 0 ans = 0 for i in range(1, n - 1): p[i] = min(maxRight - i, p[2 * pos - i]) if maxRight > i else 1 while t[i - p[i]] == t[i + p[i]]: p[i] += 1 if i + p[i] > maxRight: maxRight = i + p[i] pos = i ans += p[i] // 2 return ans # Solution 2 class Solution: def countSubstrings(self, s: str) -> int: t = '^#' + '#'.join(s) + '#$' n = len(t) p = [0 for _ in range(n)] pos, maxRight = 0, 0 ans = 0 for i in range(1, n - 1): p[i] = min(maxRight - i, p[2 * pos - i]) if maxRight > i else 1 while t[i - p[i]] == t[i + p[i]]: p[i] += 1 if i + p[i] > maxRight: maxRight = i + p[i] pos = i ans += p[i] // 2 return ans -
func countSubstrings(s string) int { ans, n := 0, len(s) for k := 0; k < n*2-1; k++ { i, j := k/2, (k+1)/2 for i >= 0 && j < n && s[i] == s[j] { ans++ i, j = i-1, j+1 } } return ans } // Solution 2 func countSubstrings(s string) int { t := "^#" for _, c := range s { t += string(c) t += "#" } t += "$" n := len(t) p := make([]int, n) pos, maxRight := 0, 0 ans := 0 for i := 1; i < n-1; i++ { if maxRight > i { mirror := 2*pos - i if p[mirror] < maxRight-i { p[i] = p[mirror] } else { p[i] = maxRight - i } } else { p[i] = 1 } for t[i-p[i]] == t[i+p[i]] { p[i]++ } if i+p[i] > maxRight { maxRight = i + p[i] pos = i } ans += p[i] / 2 } return ans } -
/** * @param {string} s * @return {number} */ var countSubstrings = function (s) { let ans = 0; const n = s.length; for (let k = 0; k < n * 2 - 1; ++k) { let i = k >> 1; let j = (k + 1) >> 1; while (~i && j < n && s[i] == s[j]) { ++ans; --i; ++j; } } return ans; }; -
// Solution 2 function countSubstrings(s: string): number { let t = '^#'; for (const c of s) { t += c + '#'; } t += '$'; const n = t.length; const p: number[] = new Array(n).fill(0); let pos = 0, maxRight = 0; let ans = 0; for (let i = 1; i < n - 1; i++) { if (maxRight > i) { p[i] = Math.min(maxRight - i, p[2 * pos - i]); } else { p[i] = 1; } while (t[i - p[i]] === t[i + p[i]]) { p[i]++; } if (i + p[i] > maxRight) { maxRight = i + p[i]; pos = i; } ans += Math.floor(p[i] / 2); } return ans; }