Teaching Kids Programming: Videos on Data Structures and Algorithms
Given a string, your task is to count how many palindromic substrings in this string. The substrings with different start indexes or end indexes are counted as different substrings even they consist of same characters.
Example 1:
Input: “abc”
Output: 3
Explanation: Three palindromic strings: “a”, “b”, “c”.Example 2:
Input: “aaa”
Output: 6
Explanation: Six palindromic strings: “a”, “a”, “a”, “aa”, “aa”, “aaa”.Note:
The input string length won’t exceed 1000.Hints:
How can we reuse a previously computed palindrome to compute a larger palindrome?
If “aba” is a palindrome, is “xabax” and palindrome? Similarly is “xabay” a palindrome?Complexity based hint:
If we use brute-force and check whether for every start and end position a substring is a palindrome we have O(n^2) start – end pairs and O(n) palindromic checks. Can we reduce the time for palindromic checks to O(1) by reusing some previous computation?
Bruteforce Algorithm to Count the Number of Palindrome Substrings
We may bruteforce all the pairs of substring indices (i, j) and check the substring s[i:j+1] to see if it is a palindrome – which can take O(N) time. The overall complexity is O(N^2*N) which is O(N^3).
1 2 3 4 5 6 7 8 9 10 | class Solution: def countSubstrings(self, s: str) -> int: n = len(s) ans = 0 for i in range(n): for j in range(i, n): a = s[i:j+1] if a == a[::-1]: ans += 1 return ans |
class Solution: def countSubstrings(self, s: str) -> int: n = len(s) ans = 0 for i in range(n): for j in range(i, n): a = s[i:j+1] if a == a[::-1]: ans += 1 return ans
In the above implementation, we reverse the substring and check for equality – we may also use the Two Pointer Algorithm to speed up the palindrome validation O(N/2).
Top Down Dynamic Programming ALgorithm to Count the Number of Palindrome Substrings
We can use Dynamic Programming Algorithm to cache the validation results for the palindrome substrings. This allows us to reduce the overall time complexity to O(N^2) and we need O(N^2) to compute all the substring palindrome validation, and O(1) to retrieve the result later.
If
Initialize all F values to True.
We can implement the Top-Down Dynamic Programming via Recursion with Memoization. Remember to use @cache, i.e. @lru_cache(None) or @lru_cache(maxsize=None) to memorize the preivous values along the calculation.
We start the Dynamic Programming process top-down.
1 2 3 4 5 6 7 8 9 | class Solution: def countSubstrings(self, s: str) -> int: @cache def f(i, j): if i > j: return True return s[i] == s[j] and f(i + 1, j - 1) n = len(s) return [f(i, j) for i in range(n) for j in range(i, n)].count(True) |
class Solution: def countSubstrings(self, s: str) -> int: @cache def f(i, j): if i > j: return True return s[i] == s[j] and f(i + 1, j - 1) n = len(s) return [f(i, j) for i in range(n) for j in range(i, n)].count(True)
Bottom Up Dynamic Programming ALgorithm to Count the Number of Palindrome Substrings
We can store the F values in an array, and start computing the validation values bottom up.
1 2 3 4 5 6 7 8 | class Solution: def countSubstrings(self, s: str) -> int: n = len(s) dp = [[True] * n for _ in range(n)] for i in range(n - 1, -1, -1): for j in range(i + 1, n): dp[i][j] = s[i] == s[j] and dp[i + 1][j - 1] return [dp[i][j] for i in range(n) for j in range(i, n)].count(True) |
class Solution: def countSubstrings(self, s: str) -> int: n = len(s) dp = [[True] * n for _ in range(n)] for i in range(n - 1, -1, -1): for j in range(i + 1, n): dp[i][j] = s[i] == s[j] and dp[i + 1][j - 1] return [dp[i][j] for i in range(n) for j in range(i, n)].count(True)
The time complexity is O(N^2) and the space complexity is also O(N^2) for both Dynamic Programming Implementations to count the number of palindrome substrings in a given string.
See also: Algorithms to Count the Number of Palindromic Substrings
–EOF (The Ultimate Computing & Technology Blog) —
Last Post: Teaching Kids Programming - Using a Stack to Remove All Adjacent Duplicates In String
Next Post: Using Depth First Search Algorithm to Complete the Minimax Tree