Given a string ‘S’, find the length of the Longest Palindromic Subsequence in it.
The Longest Palindromic Subsequence (LPS) is the problem of finding a maximum-length subsequence of a given string that is also a Palindrome.

Longest Palindromic Subsequence
Examples:
Input: S = “GEEKSFORGEEKS”
Output: 5
Explanation: The longest palindromic subsequence we can get is of length 5. There are more than 1 palindromic subsequences of length 5, for example: EEKEE, EESEE, EEFEE, …etc.
Input: S = “BBABCBCAB”
Output: 7
Explanation: As “BABCBAB” is the longest palindromic subsequence in it. “BBBBB” and “BBCBB” are also palindromic subsequences of the given sequence, but not the longest ones.
Recursive solution to find the Longest Palindromic Subsequence (LPS):
The naive solution for this problem is to generate all subsequences of the given sequence and find the longest palindromic subsequence. This solution is exponential in terms of time complexity. Let us see how this problem possesses both important properties of a Dynamic Programming (DP) Problem and can efficiently be solved using Dynamic Programming.
Following is a general recursive solution with all cases handled.
- Case1: Every single character is a palindrome of length 1
- L(i, i) = 1 (for all indexes i in given sequence)
- Case2: If first and last characters are not same
- If (X[i] != X[j]) L(i, j) = max{L(i + 1, j), L(i, j – 1)}
- Case3: If there are only 2 characters and both are same
- Else if (j == i + 1) L(i, j) = 2
- Case4: If there are more than two characters, and first and last characters are same
- Else L(i, j) = L(i + 1, j – 1) + 2
Below is the implementation for the above approach:
C++
#include <bits/stdc++.h>
using namespace std;
int max( int x, int y) { return (x > y) ? x : y; }
int lps( char * seq, int i, int j)
{
if (i == j)
return 1;
if (seq[i] == seq[j] && i + 1 == j)
return 2;
if (seq[i] == seq[j])
return lps(seq, i + 1, j - 1) + 2;
return max(lps(seq, i, j - 1), lps(seq, i + 1, j));
}
int main()
{
char seq[] = "GEEKSFORGEEKS" ;
int n = strlen (seq);
cout << "The length of the LPS is "
<< lps(seq, 0, n - 1);
return 0;
}
|
C
#include <stdio.h>
#include <string.h>
int max( int x, int y) { return (x > y) ? x : y; }
int lps( char * seq, int i, int j)
{
if (i == j)
return 1;
if (seq[i] == seq[j] && i + 1 == j)
return 2;
if (seq[i] == seq[j])
return lps(seq, i + 1, j - 1) + 2;
return max(lps(seq, i, j - 1), lps(seq, i + 1, j));
}
int main()
{
char seq[] = "GEEKSFORGEEKS" ;
int n = strlen (seq);
printf ( "The length of the LPS is %d" ,
lps(seq, 0, n - 1));
getchar ();
return 0;
}
|
Java
import java.io.*;
import java.util.*;
class GFG {
static int max( int x, int y) { return (x > y) ? x : y; }
static int lps( char seq[], int i, int j)
{
if (i == j) {
return 1 ;
}
if (seq[i] == seq[j] && i + 1 == j) {
return 2 ;
}
if (seq[i] == seq[j]) {
return lps(seq, i + 1 , j - 1 ) + 2 ;
}
return max(lps(seq, i, j - 1 ), lps(seq, i + 1 , j));
}
public static void main(String[] args)
{
String seq = "GEEKSFORGEEKS" ;
int n = seq.length();
System.out.printf( "The length of the LPS is %d" ,
lps(seq.toCharArray(), 0 , n - 1 ));
}
}
|
Python3
def max (x, y):
if (x > y):
return x
return y
def lps(seq, i, j):
if (i = = j):
return 1
if (seq[i] = = seq[j] and i + 1 = = j):
return 2
if (seq[i] = = seq[j]):
return lps(seq, i + 1 , j - 1 ) + 2
return max (lps(seq, i, j - 1 ),
lps(seq, i + 1 , j))
if __name__ = = '__main__' :
seq = "GEEKSFORGEEKS"
n = len (seq)
print ( "The length of the LPS is" ,
lps(seq, 0 , n - 1 ))
|
C#
using System;
public class GFG {
static int max( int x, int y) { return (x > y) ? x : y; }
static int lps( char [] seq, int i, int j)
{
if (i == j) {
return 1;
}
if (seq[i] == seq[j] && i + 1 == j) {
return 2;
}
if (seq[i] == seq[j]) {
return lps(seq, i + 1, j - 1) + 2;
}
return max(lps(seq, i, j - 1), lps(seq, i + 1, j));
}
public static void Main()
{
String seq = "GEEKSFORGEEKS" ;
int n = seq.Length;
Console.Write( "The length of the LPS is "
+ lps(seq.ToCharArray(), 0, n - 1));
}
}
|
Javascript
function max(x, y)
{
return (x > y) ? x : y;
}
function lps(seq, i, j)
{
if (i == j)
{
return 1;
}
if (seq[i] == seq[j] && i + 1 == j)
{
return 2;
}
if (seq[i] == seq[j])
{
return lps(seq, i + 1, j - 1) + 2;
}
return max(lps(seq, i, j - 1), lps(seq, i + 1, j));
}
let seq = "GEEKSFORGEEKS" ;
let n = seq.length;
console.log( "The length of the LPS is " , lps(seq.split( "" ), 0, n - 1));
|
Output
The length of the LPS is 5
Time complexity: O(2n), where ‘n’ is the length of the input sequence.
Auxiliary Space: O(n2) as we are using a 2D array to store the solutions of the subproblems.
Using the Memoization Technique of Dynamic Programming:
The idea used here is to reverse the given input string and check the length of the longest common subsequence. That would be the answer for the longest palindromic subsequence.
Below is the implementation for the above approach:
C++
#include <bits/stdc++.h>
using namespace std;
int dp[1001][1001];
int lps(string& s1, string& s2, int n1, int n2)
{
if (n1 == 0 || n2 == 0) {
return 0;
}
if (dp[n1][n2] != -1) {
return dp[n1][n2];
}
if (s1[n1 - 1] == s2[n2 - 1]) {
return dp[n1][n2] = 1 + lps(s1, s2, n1 - 1, n2 - 1);
}
else {
return dp[n1][n2] = max(lps(s1, s2, n1 - 1, n2),
lps(s1, s2, n1, n2 - 1));
}
}
int main()
{
string seq = "GEEKSFORGEEKS" ;
int n = seq.size();
dp[n][n];
memset (dp, -1, sizeof (dp));
string s2 = seq;
reverse(s2.begin(), s2.end());
cout << "The length of the LPS is "
<< lps(s2, seq, n, n) << endl;
return 0;
}
|
Java
import java.io.*;
import java.util.*;
class GFG {
static int max( int x, int y) { return (x > y) ? x : y; }
static int lps( char seq[], int i, int j, int dp[][])
{
if (i == j) {
return dp[i][j] = 1 ;
}
if (seq[i] == seq[j] && i + 1 == j) {
return dp[i][j] = 2 ;
}
if (dp[i][j] != - 1 ) {
return dp[i][j];
}
if (seq[i] == seq[j]) {
return dp[i][j]
= lps(seq, i + 1 , j - 1 , dp) + 2 ;
}
return dp[i][j] = max(lps(seq, i, j - 1 , dp),
lps(seq, i + 1 , j, dp));
}
public static void main(String[] args)
{
String seq = "GEEKSFORGEEKS" ;
int n = seq.length();
int dp[][] = new int [n][n];
for ( int [] arr : dp)
Arrays.fill(arr, - 1 );
System.out.printf(
"The length of the LPS is %d" ,
lps(seq.toCharArray(), 0 , n - 1 , dp));
}
}
|
Python3
dp = [[ - 1 for i in range ( 1001 )] for j in range ( 1001 )]
def lps(s1, s2, n1, n2):
if (n1 = = 0 or n2 = = 0 ):
return 0
if (dp[n1][n2] ! = - 1 ):
return dp[n1][n2]
if (s1[n1 - 1 ] = = s2[n2 - 1 ]):
dp[n1][n2] = 1 + lps(s1, s2, n1 - 1 , n2 - 1 )
return dp[n1][n2]
else :
dp[n1][n2] = max (lps(s1, s2, n1 - 1 , n2), lps(s1, s2, n1, n2 - 1 ))
return dp[n1][n2]
seq = "GEEKSFORGEEKS"
n = len (seq)
s2 = seq
s2 = s2[:: - 1 ]
print (f "The length of the LPS is {lps(s2, seq, n, n)}" )
|
C#
using System;
using System.Numerics;
using System.Collections.Generic;
public class GFG {
static int max( int x, int y) { return (x > y) ? x : y; }
static int lps( char [] seq, int i, int j)
{
if (i == j) {
return 1;
}
if (seq[i] == seq[j] && i + 1 == j) {
return 2;
}
if (seq[i] == seq[j]) {
return lps(seq, i + 1, j - 1) + 2;
}
return max(lps(seq, i, j - 1), lps(seq, i + 1, j));
}
public static void Main( string [] args)
{
string seq = "GEEKSFORGEEKS" ;
int n = seq.Length;
Console.Write( "The length of the LPS is "
+ lps(seq.ToCharArray(), 0, n - 1));
}
}
|
Javascript
let dp;
function lps(s1, s2, n1, n2)
{
if (n1 == 0 || n2 == 0) {
return 0;
}
if (dp[n1][n2] != -1) {
return dp[n1][n2];
}
if (s1[n1 - 1] == s2[n2 - 1]) {
return dp[n1][n2] = 1 + lps(s1, s2, n1 - 1, n2 - 1);
}
else {
return dp[n1][n2] = Math.max(lps(s1, s2, n1 - 1, n2),
lps(s1, s2, n1, n2 - 1));
}
}
let seq = "GEEKSFORGEEKS" ;
let n = seq.length;
dp = new Array(1001);
for (let i=0;i<1001;i++){
dp[i] = new Array(1001).fill(-1);
}
let s2 = seq;
s2 = s2.split( '' ).reverse().join( '' );
console.log( "The length of the LPS is " + lps(s2, seq, n, n), "</br>" );
|
Output
The length of the LPS is 5
Time Complexity: O(n2)
Auxiliary Space: O(n2)
Using the Tabulation technique of Dynamic programming to find LPS:
In the earlier sections, we discussed recursive and dynamic programming approaches with memoization for solving the Longest Palindromic Subsequence (LPS) problem. Now, we will shift our focus to the Bottom-up dynamic programming method.
Below is the implementation for the above approach:
C++
#include <algorithm>
#include <cstring> // for memset
#include <iostream>
#include <string>
using namespace std;
int longestPalinSubseq(string S)
{
string R = S;
reverse(R.begin(), R.end());
int dp[S.length() + 1][R.length() + 1];
memset (dp, 0, sizeof (dp));
for ( int i = 1; i <= S.length(); i++) {
for ( int j = 1; j <= R.length(); j++) {
if (S[i - 1] == R[j - 1])
dp[i][j] = 1 + dp[i - 1][j - 1];
else
dp[i][j] = max(dp[i][j - 1], dp[i - 1][j]);
}
}
return dp[S.length()][R.length()];
}
int main()
{
string s = "GEEKSFORGEEKS" ;
cout << "The length of the LPS is "
<< longestPalinSubseq(s) << endl;
return 0;
}
|
Java
import java.io.*;
import java.util.*;
class GFG {
public static int longestPalinSubseq(String S)
{
String R
= new StringBuilder(S).reverse().toString();
int dp[][]
= new int [S.length() + 1 ][R.length() + 1 ];
for ( int i = 1 ; i <= S.length(); i++) {
for ( int j = 1 ; j <= R.length(); j++) {
if (S.charAt(i - 1 ) == R.charAt(j - 1 ))
dp[i][j] = 1 + dp[i - 1 ][j - 1 ];
else
dp[i][j] = Math.max(dp[i][j - 1 ],
dp[i - 1 ][j]);
}
}
return dp[S.length()][R.length()];
}
public static void main(String[] args)
{
String s = "GEEKSFORGEEKS" ;
System.out.println( "The length of the LPS is "
+ longestPalinSubseq(s));
}
}
|
Python3
def longestPalinSubseq(S):
R = S[:: - 1 ]
dp = [[ 0 ] * ( len (R) + 1 ) for _ in range ( len (S) + 1 )]
for i in range ( 1 , len (S) + 1 ):
for j in range ( 1 , len (R) + 1 ):
if S[i - 1 ] = = R[j - 1 ]:
dp[i][j] = 1 + dp[i - 1 ][j - 1 ]
else :
dp[i][j] = max (dp[i][j - 1 ], dp[i - 1 ][j])
return dp[ len (S)][ len (R)]
s = "GEEKSFORGEEKS"
print ( "The length of the LPS is" , longestPalinSubseq(s))
|
C#
using System;
public class GFG {
static int LongestPalinSubseq( string S)
{
char [] charArray = S.ToCharArray();
Array.Reverse(charArray);
string R = new string (charArray);
int [, ] dp = new int [S.Length + 1, R.Length + 1];
for ( int i = 0; i <= S.Length; i++) {
for ( int j = 0; j <= R.Length; j++) {
dp[i, j] = 0;
}
}
for ( int i = 1; i <= S.Length; i++) {
for ( int j = 1; j <= R.Length; j++) {
if (S[i - 1] == R[j - 1])
dp[i, j] = 1 + dp[i - 1, j - 1];
else
dp[i, j] = Math.Max(dp[i, j - 1],
dp[i - 1, j]);
}
}
return dp[S.Length, R.Length];
}
public static void Main( string [] args)
{
string s = "GEEKSFORGEEKS" ;
Console.WriteLine( "The length of the LPS is "
+ LongestPalinSubseq(s));
}
}
|
Javascript
function longestPalinSubseq(S)
{
let R = S.split( '' ).reverse().join( '' );
let dp = new Array(S.length + 1).fill(0).map(() => new Array(R.length + 1).fill(0));
for (let i = 1; i <= S.length; i++) {
for (let j = 1; j <= R.length; j++) {
if (S[i - 1] == R[j - 1])
dp[i][j] = 1 + dp[i - 1][j - 1];
else
dp[i][j] = Math.max(dp[i][j - 1], dp[i - 1][j]);
}
}
return dp[S.length][R.length];
}
let s = "GEEKSFORGEEKS" ;
console.log( "The length of the LPS is " + longestPalinSubseq(s));
|
Output
The length of the LPS is 5
Time Complexity : O(n2)
Auxiliary Space: O(n2), since we use a 2-D array.
Feeling lost in the world of random DSA topics, wasting time without progress? It's time for a change! Join our DSA course, where we'll guide you on an exciting journey to master DSA efficiently and on schedule.
Ready to dive in? Explore our Free Demo Content and join our DSA course, trusted by over 100,000 geeks!
Last Updated :
29 Aug, 2023
Like Article
Save Article