Longest Palindromic Subsequence

Learn via video course
FREE
View all courses
DSA Problem Solving for Interviews using Java
DSA Problem Solving for Interviews using Java
by Jitender Punia
1000
4.9
Start Learning
DSA Problem Solving for Interviews using Java
DSA Problem Solving for Interviews using Java
by Jitender Punia
1000
4.9
Start Learning
Topics Covered

Problem Statement

Given a string 'S', your objective is to identify the length of the longest palindromic subsequence. In simpler terms, you're tasked with finding the longest sequence of characters in 'S' that can be read the same forwards and backwards, but not necessarily in consecutive order.

Example

Palindromic Subsequence

Approach-1: Using Recursive Solution

  1. Base case: If a single character is considered, it's always a palindrome of length 1.
  2. If the first and last characters are different: In this case, the length of the LPS is the maximum of either excluding the first character or excluding the last character.
  3. If there are only 2 characters and both are the same: In this scenario, the length of the LPS is 2.
  4. If the first and last characters are the same: Here, we add 2 to the length of the LPS of the substring excluding the first and last characters.

Dry Run:

Longest Palindromic Subsequence

Code Implementation

C++:

Java:

Python:

Output :

Complexity Analysis

  • Time Complexity - Since we are recurring for each subsequence of string ss, the overall time complexity is equal to the number of possible subsequences which is nothing but O(2n)O(2^n).
  • Space Complexity - Though we are not using any auxiliary data structure, due to multiple sub-problems the maximum height of the recursive stack can reach up to nn, hence overall space complexity is O(n)O(n).

Approach-2: Memoization Technique

  1. Create a Memoization Table: Initialize a 2D memoization table dp of size n x n. Initialize all values in dp to -1 initially.
  2. Modify the Recursive Function: Modify the recursive function to check the memoization table before making recursive calls. If the value for the current indices (i, j) is already computed, return the stored value from the memoization table.

Code Implementation

C++:

Java:

Python:

Output:

Complexity Analysis

  • Time Complexity - The time complexity of memoization code has now been reduced to O(n2)O(n^2) from O(2n)O(2^n), due to which the problem becomes solvable as per the given constraints of the question.
  • Space Complexity - As we are using an auxiliary 2-D array of dimension n×nn\times n due to which the space complexity becomes O(n×n)=O(n2)O(n\times n) = O(n^2).

Approach-3: Using the Tabulation Technique of Dynamic Programming

We will define our DP state i.e.i.e. dp[i][j] which denotes the length of the LPS of the string s[i...j]s[i...j]. Then we will see the state transitions -

dp[i][j]={2+dp[i+1][j1],If s[i] == s[j]max(dp[i+1][j], dp[i][j1]),Otherwisedp[i][j] = \begin{cases} 2 + dp[i+1][j-1], & \text{If s[i] == s[j]}\\ max (dp[i+1][j], \space dp[i][j-1]), & \text{Otherwise} \end{cases}

Algorithm

Now we will use the gap strategy to fill the dp table step-by-step using the following logic. Let ss be the string of length nn, we will start filling the dp table for all substring with gap 0 then with gap 1, and so on till the gap of n1n-1. Here gap=kgap=k means all substring with gap kk i.ei.e s[i...j]s[i...j] such that ji=kj-i=k.

  • Declare a 2-D array dpdp of size n×nn\times n.
  • Iterate for gap=0gap = 0 to gap=n1gap = n-1 and do the following -
  • Declare a variable say ii and initialize it to 0.
  • Iterate for j=gapj=gap to j=n1j=n-1 and do the following -
  • Fill the dp[i][j] as per the state transitions described above.
  • Increment i by 1, i.e.i.e. i++
  • Now dp[0][n-1] will contain the length of the LPS for string s[0...n1]s[0...n-1] i.e.i.e. original string. Hence, we will return it as the answer.

Code Implementation

C++:

Java:

Python:

Output:

Complexity Analysis

  • Time Complexity - In the first iteration the inner loop runs for nn time, in the second iteration it runs for n1n-1 time, and similarly in the (n1)th(n-1)^{th} iteration inner loop runs for 1 time. Hence the total number of executions of the inner loop is n+(n1)+(n2)+...+1n + (n-1) + (n-2)+...+1 which is an order of n2n^2 and hence the time complexity is O(n2)O(n^2).
  • Space Complexity - We have used a 2-D array of dimension n×nn\times n due to which the space complexity is O(n2)O(n^2).

Explore Scaler Topics Data Structures Tutorial and enhance your DSA skills with Reading Tracks and Challenges.

Conclusion

  1. Problem Definition: The Longest Palindromic Subsequence (LPS) problem involves finding the length of the longest subsequence in a given string that reads the same forwards and backwards.
  2. Naive Approach: A naive solution of longest palindromic subsequence problem involves generating all possible subsequences of the given string and checking each one for palindromic properties. However, this approach is exponential in time complexity.
  3. Dynamic Programming: By applying dynamic programming techniques to longest palindromic subsequence problem, it can be efficiently solved. This involves breaking down the problem into smaller subproblems and storing their solutions to avoid redundant computations.
  4. Memoization Technique: Memoization involves storing the results of previously computed subproblems to avoid recalculating them. This significantly reduces the time complexity by eliminating redundant recursive calls.
  5. Tabulation Technique: Another dynamic programming approach involves filling up a table iteratively, bottom-up, starting from smaller subproblems to larger ones. This method further enhances efficiency by eliminating recursion overhead of longest palindromic subsequence problem.
  6. Complexity Analysis: Both memoization and tabulation techniques achieve a time complexity of O(n^2) and a space complexity of O(n^2), making the problem solvable within reasonable time and space constraints for large inputs.