0% completed
Problem Statement
Given a string, find the length of its Longest Palindromic Substring (LPS). In a palindromic string, elements read the same backward and forward.
Example 1:
Input: "abdbca"
Output: 3
Explanation: LPS is "bdb".
Example 2:
Input: = "cddpd"
Output: 3
Explanation: LPS is "dpd".
Example 3:
Input: = "pqr"
Output: 1
Explanation: LPS could be "p", "q" or "r".
Constraints:
1 <= st.length <= 1000
st
consists only of lowercase English letters.
Basic Solution
This problem follows the "Longest Palindromic Subsequence"
pattern. The only difference is that in a palindromic subsequence characters can be non-adjacent, whereas in a substring all characters should form a palindrome. We will follow a similar approach though.
The brute-force solution will be to try all the substrings of the given string. We can start processing from the beginning and the end of the string. So at any step, we will have two options:
- If the element at the beginning and the end are the same, we make a recursive call to check if the remaining substring is also a palindrome. If so, the substring is a palindrome from beginning to end.
- We will skip either the element from the beginning or the end to make two recursive calls for the remaining substring. The length of LPS would be the maximum of these two recursive calls.
Here is the code:
Due to the three recursive calls, the time complexity of the above algorithm is exponential O(3^n), where 'n' is the length of the input string. The space complexity is O(n) which is used to store the recursion stack.
Top-down Dynamic Programming with Memoization
We can use an array to store the already solved subproblems.
The two changing values to our recursive function are the two indexes, startIndex and endIndex. Therefore, we can store the results of all the subproblems in a two-dimensional array. (Another alternative could be to use a hash-table whose key would be a string (startIndex + "|" + endIndex))
Here is the code for this:
The above algorithm has a time and space complexity of O(n^2) because we will not have more than n*n subproblems.
Bottom-up Dynamic Programming
Since we want to try all the substrings of the given string, we can use a two-dimensional array to store the subproblems' results. So dp[i][j]
will be 'true' if the substring from index 'i' to index 'j' is a palindrome.
We can start from the beginning of the string and keep adding one element at a time. At every step, we will try all of its substrings. So for every endIndex
and startIndex
in the given string, we need to check the following thing:
If the element at the startIndex
matches the element at the endIndex
, we will further check if the remaining substring (from startIndex+1
to endIndex-1
) is a substring too.
So our recursive formula will look like:
if st[startIndex] == st[endIndex], and if the remaing string is of zero length or dp[startIndex+1][endIndex-1] is a palindrome then dp[startIndex][endIndex] = true
Let's draw this visually for "cddpd", starting with a substring of length '1'. As we know, every substring with one element is a palindrome:

![startIndex:3, endIndex:4 => since st[startIndex] != st[endIndex] => false](/_next/image?url=https%3A%2F%2Fstorage.googleapis.com%2Fdownload%2Fstorage%2Fv1%2Fb%2Fdesigngurus-prod.appspot.com%2Fo%2FdocImages%252F637f54e6a842de869cd5f13f%252Fimg%3A36cbd3-f5f6-2564-c5c3-710107b5466.jpg%3Fgeneration%3D1669289419809489%26alt%3Dmedia&w=3840&q=75&dpl=dpl_77Ae7vEwq3A8eA9La8V6vjrYv3GG)
![startIndex:2, endIndex:3 => since st[startIndex] != st[endIndex] => false](/_next/image?url=https%3A%2F%2Fstorage.googleapis.com%2Fdownload%2Fstorage%2Fv1%2Fb%2Fdesigngurus-prod.appspot.com%2Fo%2FdocImages%252F637f54e6a842de869cd5f13f%252Fimg%3A6ad4571-e5-840e-6836-7d8234dbfbc.jpg%3Fgeneration%3D1669289443675181%26alt%3Dmedia&w=3840&q=75&dpl=dpl_77Ae7vEwq3A8eA9La8V6vjrYv3GG)
![startIndex:2, endIndex:4 => since st[startIndex] == st[endIndex] and dp[startIndex+1][endIndex-1] is true => true](/_next/image?url=https%3A%2F%2Fstorage.googleapis.com%2Fdownload%2Fstorage%2Fv1%2Fb%2Fdesigngurus-prod.appspot.com%2Fo%2FdocImages%252F637f54e6a842de869cd5f13f%252Fimg%3Abbb6bf0-3283-20dd-20d1-f8074fca778.jpg%3Fgeneration%3D1669289482206213%26alt%3Dmedia&w=3840&q=75&dpl=dpl_77Ae7vEwq3A8eA9La8V6vjrYv3GG)
![startIndex:1, endIndex:2 => since st[startIndex] == st[endIndex] and it is a two character string => true](/_next/image?url=https%3A%2F%2Fstorage.googleapis.com%2Fdownload%2Fstorage%2Fv1%2Fb%2Fdesigngurus-prod.appspot.com%2Fo%2FdocImages%252F637f54e6a842de869cd5f13f%252Fimg%3Aaabda0-88b-dcdc-daa2-8fd800cfd07.jpg%3Fgeneration%3D1669289529132685%26alt%3Dmedia&w=3840&q=75&dpl=dpl_77Ae7vEwq3A8eA9La8V6vjrYv3GG)
![startIndex:1, endIndex:3 => since st[startIndex] != st[endIndex] => false](/_next/image?url=https%3A%2F%2Fstorage.googleapis.com%2Fdownload%2Fstorage%2Fv1%2Fb%2Fdesigngurus-prod.appspot.com%2Fo%2FdocImages%252F637f54e6a842de869cd5f13f%252Fimg%3Ae104eb-d0f3-b5b6-84ca-4d2ed2d0f408.jpg%3Fgeneration%3D1669289550219574%26alt%3Dmedia&w=3840&q=75&dpl=dpl_77Ae7vEwq3A8eA9La8V6vjrYv3GG)
![startIndex:1, endIndex:4 => since st[startIndex] == st[endIndex] but dp[startIndex+1][endIndex-1] is false => false](/_next/image?url=https%3A%2F%2Fstorage.googleapis.com%2Fdownload%2Fstorage%2Fv1%2Fb%2Fdesigngurus-prod.appspot.com%2Fo%2FdocImages%252F637f54e6a842de869cd5f13f%252Fimg%3A14606c-b4f-61-242-5361303e005.jpg%3Fgeneration%3D1669289581947110%26alt%3Dmedia&w=3840&q=75&dpl=dpl_77Ae7vEwq3A8eA9La8V6vjrYv3GG)
![startIndex:0, endIndex:1-4 => since st[startIndex] != st[endIndex] => false](/_next/image?url=https%3A%2F%2Fstorage.googleapis.com%2Fdownload%2Fstorage%2Fv1%2Fb%2Fdesigngurus-prod.appspot.com%2Fo%2FdocImages%252F637f54e6a842de869cd5f13f%252Fimg%3Acfd610-ef5b-4eb4-c76e-0c4265e008.jpg%3Fgeneration%3D1669289618852150%26alt%3Dmedia&w=3840&q=75&dpl=dpl_77Ae7vEwq3A8eA9La8V6vjrYv3GG)
Here is the code for our bottom-up dynamic programming approach:
The time and space complexity of the above algorithm is O(n^2), where 'n' is the length of the input string.
Manacher's Algorithm
The best-known algorithm to find the longest palindromic substring which runs in linear time O(n) is Manacher's Algorithm. However, it is a non-trivial algorithm that doesn't use DP. Please take a look to familiarize yourself with this algorithm, however, no one expects you to come up with such an algorithm in a 45 minutes coding interview.
.....
.....
.....
Table of Contents
Contents are not accessible
Contents are not accessible
Contents are not accessible
Contents are not accessible
Contents are not accessible