Improve
Suggest changes
Like Article
Like
Report
Try it on GfG Practice
redirect icon

Given a string s, find the length of the Longest Palindromic Subsequence in it.

Note: The Longest Palindromic Subsequence (LPS) is the maximum-length subsequence of a given string that is also a Palindrome.

[画像:LPS]
Longest Palindromic Subsequence

Examples:

Input: s = "bbabcbcab"
Output: 7
Explanation: Subsequence "babcbab" is the longest subsequence which is also a palindrome.

Input: s = "abcd"
Output: 1
Explanation: "a", "b", "c" and "d" are palindromic and all have a length 1.

Table of Content

[Naive Approach] - Using Recursion - O(2^n) Time and O(1) Space

The idea is to recursively generate all possible subsequences of the given string s and find the longest palindromic subsequence. To do so, create two counters low and high and set them to point to first and last character of string s. Start matching the characters from both the ends of the string. For each case, there are two possibilities:

C++
// C++ program to find the lps
#include<bits/stdc++.h>
usingnamespacestd;
// Returns the length of the longest 
// palindromic subsequence in seq
intlps(conststring&s,intlow,inthigh){
// Base case
if(low>high)return0;

// If there is only 1 character
if(low==high)
return1;
// If the first and last characters match
if(s[low]==s[high])
returnlps(s,low+1,high-1)+2;
// If the first and last characters do not match
returnmax(lps(s,low,high-1),lps(s,low+1,high));
}
intlongestPalinSubseq(string&s){
returnlps(s,0,s.size()-1);
}
intmain(){
strings="bbabcbcab";
cout<<longestPalinSubseq(s);
return0;
}
C
// C program to find the lps
#include<stdio.h>
#include<string.h>
// Returns the length of the longest 
// palindromic subsequence in seq
intlps(constchar*s,intlow,inthigh){
// Base case
if(low>high)return0;
// If there is only 1 character
if(low==high)
return1;
// If the first and last characters match
if(s[low]==s[high])
returnlps(s,low+1,high-1)+2;
// If the first and last characters do not match

inta=lps(s,low,high-1);
intb=lps(s,low+1,high);
return(a>b)?a:b;
}
intlongestPalinSubseq(char*s){
intn=strlen(s);
returnlps(s,0,n-1);
}
intmain(){
chars[]="bbabcbcab";
printf("%d",longestPalinSubseq(s));
return0;
}
Java
// Java program to find the lps
class GfG{
// Returns the length of the longest 
// palindromic subsequence in seq
staticintlps(Strings,intlow,inthigh){
// Base case
if(low>high)return0;
// If there is only 1 character
if(low==high)
return1;
// If the first and last characters match
if(s.charAt(low)==s.charAt(high))
returnlps(s,low+1,high-1)+2;
// If the first and last characters do not match
returnMath.max(lps(s,low,high-1),lps(s,low+1,high));
}
staticintlongestPalinSubseq(Strings){
returnlps(s,0,s.length()-1);
}
publicstaticvoidmain(String[]args){
Strings="bbabcbcab";
System.out.println(longestPalinSubseq(s));
}
}
Python
# Python program to find the lps
# Returns the length of the longest 
# palindromic subsequence in seq
def lps(s, low, high):
 # Base case
 if low > high:
 return 0
 # If there is only 1 character
 if low == high:
 return 1
 # If the first and last characters match
 if s[low] == s[high]:
 return lps(s, low + 1, high - 1) + 2
 # If the first and last characters do not match
 return max(lps(s, low, high - 1), lps(s, low + 1, high))
def longestPalinSubseq(s):
 return lps(s, 0, len(s) - 1)
if __name__ == "__main__":
 s = "bbabcbcab"
 print(longestPalinSubseq(s))
C#
// C# program to find the lps
usingSystem;
classGfG{
// Returns the length of the longest 
// palindromic subsequence in seq
staticintlps(strings,intlow,inthigh){
// Base case
if(low>high)return0;
// If there is only 1 character
if(low==high)
return1;
// If the first and last characters match
if(s[low]==s[high])
returnlps(s,low+1,high-1)+2;
// If the first and last characters do not match
returnMath.Max(lps(s,low,high-1),
lps(s,low+1,high));
}
staticintlongestPalinSubseq(strings){
returnlps(s,0,s.Length-1);
}
staticvoidMain(string[]args){
strings="bbabcbcab";
Console.WriteLine(longestPalinSubseq(s));
}
}
JavaScript
// JavaScript program to find the lps
// Returns the length of the longest 
// palindromic subsequence in seq
functionlps(s,low,high){
// Base case
if(low>high)return0;
// If there is only 1 character
if(low===high)
return1;
// If the first and last characters match
if(s[low]===s[high])
returnlps(s,low+1,high-1)+2;
// If the first and last characters do not match
returnMath.max(lps(s,low,high-1),
lps(s,low+1,high));
}
functionlongestPalinSubseq(s){
returnlps(s,0,s.length-1);
}
consts="bbabcbcab";
console.log(longestPalinSubseq(s));

Output
7

[Better Approach 1] Using Memoization - O(n^2) Time and O(n^2) Space

In the above approach, lps() function is calculating the same substring multiple times. The idea is to use memoization to store the result of subproblems thus avoiding repetition. To do so, create a 2d array memo[][] of order n*n, where memo[i][j] stores the length of LPS of substring s[i] to s[j]. At each step, check if the substring is already calculated, if so return the stored value else operate as in above approach.

C++
// C++ program to find the lps
#include<bits/stdc++.h>
usingnamespacestd;
// Returns the length of the longest 
// palindromic subsequence in seq
intlps(conststring&s,intlow,inthigh,
vector<vector<int>>&memo){
// Base case
if(low>high)return0;

// If there is only 1 character
if(low==high)
return1;
// If the value is already calculated
if(memo[low][high]!=-1)
returnmemo[low][high];
// If the first and last characters match
if(s[low]==s[high])
returnmemo[low][high]=
lps(s,low+1,high-1,memo)+2;
// If the first and last characters do not match
returnmemo[low][high]=
max(lps(s,low,high-1,memo),
lps(s,low+1,high,memo));
}
intlongestPalinSubseq(string&s){
// create memoization table
vector<vector<int>>memo(s.size(),
vector<int>(s.size(),-1));
returnlps(s,0,s.size()-1,memo);
}
intmain(){
strings="bbabcbcab";
cout<<longestPalinSubseq(s);
return0;
}
Java
// Java program to find the lps
class GfG{
// Returns the length of the longest 
// palindromic subsequence in seq
staticintlps(Strings,intlow,inthigh,int[][]memo){
// Base case
if(low>high)return0;
// If there is only 1 character
if(low==high)
return1;
// If the value is already calculated
if(memo[low][high]!=-1)
returnmemo[low][high];
// If the first and last characters match
if(s.charAt(low)==s.charAt(high))
returnmemo[low][high]=
lps(s,low+1,high-1,memo)+2;
// If the first and last characters do not match
returnmemo[low][high]=
Math.max(lps(s,low,high-1,memo),
lps(s,low+1,high,memo));
}
staticintlongestPalinSubseq(Strings){
// create memoization table
intn=s.length();
int[][]memo=newint[n][n];
for(inti=0;i<n;i++){
for(intj=0;j<n;j++){
memo[i][j]=-1;
}
}
returnlps(s,0,n-1,memo);
}
publicstaticvoidmain(String[]args){
Strings="bbabcbcab";
System.out.println(longestPalinSubseq(s));
}
}
Python
# Python program to find the lps
# Returns the length of the longest 
# palindromic subsequence in seq
def lps(s, low, high, memo):
 # Base case
 if low > high:
 return 0
 # If there is only 1 character
 if low == high:
 return 1
 # If the value is already calculated
 if memo[low][high] != -1:
 return memo[low][high]
 # If the first and last characters match
 if s[low] == s[high]:
 memo[low][high] = lps(s, low + 1, high - 1, memo) + 2
 
 else:
 # If the first and last characters do not match
 memo[low][high] = max(lps(s, low, high - 1, memo), 
 lps(s, low + 1, high, memo))
 return memo[low][high]
def longestPalinSubseq(s):
 n = len(s)
 memo = [[-1 for _ in range(n)] for _ in range(n)]
 return lps(s, 0, n - 1, memo)
if __name__ == "__main__":
 s = "bbabcbcab"
 print(longestPalinSubseq(s))
C#
// C# program to find the lps
usingSystem;
classGfG{
// Returns the length of the longest 
// palindromic subsequence in seq
staticintlps(strings,intlow,
inthigh,int[,]memo){
// Base case
if(low>high)return0;
// If there is only 1 character
if(low==high)
return1;
// If the value is already calculated
if(memo[low,high]!=-1)
returnmemo[low,high];
// If the first and last characters match
if(s[low]==s[high])
returnmemo[low,high]=
lps(s,low+1,high-1,memo)+2;
// If the first and last characters do not match
returnmemo[low,high]=
Math.Max(lps(s,low,high-1,memo),
lps(s,low+1,high,memo));
}
staticintlongestPalinSubseq(strings){
// create memoization table
intn=s.Length;
int[,]memo=newint[n,n];
for(inti=0;i<n;i++){
for(intj=0;j<n;j++){
memo[i,j]=-1;
}
}
returnlps(s,0,n-1,memo);
}
staticvoidMain(string[]args){
strings="bbabcbcab";
Console.WriteLine(longestPalinSubseq(s));
}
}
JavaScript
// JavaScript program to find the lps
// Returns the length of the longest 
// palindromic subsequence in seq
functionlps(s,low,high,memo){
// Base case
if(low>high)return0;
// If there is only 1 character
if(low===high)
return1;
// If the value is already calculated
if(memo[low][high]!==-1)
returnmemo[low][high];
// If the first and last characters match
if(s[low]===s[high]){
memo[low][high]=lps(s,low+1,high-1,memo)+2;
}else{
// If the first and last characters do not match
memo[low][high]=Math.max(
lps(s,low,high-1,memo),
lps(s,low+1,high,memo)
);
}
returnmemo[low][high];
}
functionlongestPalinSubseq(s){
constn=s.length;
constmemo=Array.from({length:n},
()=>Array(n).fill(-1));
returnlps(s,0,n-1,memo);
}
consts="bbabcbcab";
console.log(longestPalinSubseq(s));

Output
7

[Better Approach 2] Using Tabulation - O(n^2) Time and O(n^2) Space

The above approach can be implemented using tabulation to minimize the auxiliary space required for recursive stack. The idea is create a 2d array dp[][] of order n*n, where element dp[i][j] stores the length of LPS of substring s[i] to s[j]. Start from the smaller substring and try to build answers for longer ones. At each step there are two possibilities:

dp[0][n-1] stores the length of the longest palindromic subsequence of string s.

C++
// C++ program to find the lps
#include<bits/stdc++.h>
usingnamespacestd;
// Function to find the LPS
intlongestPalinSubseq(string&s){
intn=s.length();
// Create a DP table
vector<vector<int>>dp(n,vector<int>(n));
// Build the DP table for all the substrings
for(inti=n-1;i>=0;i--){
for(intj=i;j<n;j++){
// If there is only one character
if(i==j){
dp[i][j]=1;
continue;
}
// If characters at position i and j are the same
if(s[i]==s[j]){
if(i+1==j)dp[i][j]=2;
elsedp[i][j]=dp[i+1][j-1]+2;
}
else{
// Otherwise, take the maximum length
// from either excluding i or j
dp[i][j]=max(dp[i+1][j],dp[i][j-1]);
}
}
}
// The final answer is stored in dp[0][n-1]
returndp[0][n-1];
}
intmain(){
strings="bbabcbcab";
cout<<longestPalinSubseq(s);
return0;
}
Java
// Java program to find the lps
class GfG{
// Function to find the LPS
staticintlongestPalinSubseq(Strings){
intn=s.length();
// Create a DP table
int[][]dp=newint[n][n];
// Build the DP table for all the substrings
for(inti=n-1;i>=0;i--){
for(intj=i;j<n;j++){
// If there is only one character
if(i==j){
dp[i][j]=1;
continue;
}
// If characters at position i and j are the same
if(s.charAt(i)==s.charAt(j)){
if(i+1==j)dp[i][j]=2;
elsedp[i][j]=dp[i+1][j-1]+2;
}
else{
// Otherwise, take the maximum length
// from either excluding i or j
dp[i][j]=Math.max(dp[i+1][j],dp[i][j-1]);
}
}
}
// The final answer is stored in dp[0][n-1]
returndp[0][n-1];
}
publicstaticvoidmain(String[]args){
Strings="bbabcbcab";
System.out.println(longestPalinSubseq(s));
}
}
Python
# Python program to find the lps
# Function to find the LPS
def longestPalinSubseq(s):
 n = len(s)
 # Create a DP table
 dp = [[0] * n for _ in range(n)]
 # Build the DP table for all the substrings
 for i in range(n - 1, -1, -1):
 for j in range(i, n):
 # If there is only one character
 if i == j:
 dp[i][j] = 1
 continue
 # If characters at position i and j are the same
 if s[i] == s[j]:
 if i + 1 == j:
 dp[i][j] = 2
 else:
 dp[i][j] = dp[i + 1][j - 1] + 2
 else:
 # Otherwise, take the maximum length
 # from either excluding i or j
 dp[i][j] = max(dp[i + 1][j], dp[i][j - 1])
 # The final answer is stored in dp[0][n-1]
 return dp[0][n - 1]
if __name__ == "__main__":
 s = "bbabcbcab"
 print(longestPalinSubseq(s))
C#
// C# program to find the lps
usingSystem;
classGfG{
// Function to find the LPS
staticintlongestPalinSubseq(strings){
intn=s.Length;
// Create a DP table
int[,]dp=newint[n,n];
// Build the DP table for all the substrings
for(inti=n-1;i>=0;i--){
for(intj=i;j<n;j++){
// If there is only one character
if(i==j){
dp[i,j]=1;
continue;
}
// If characters at position i and j are the same
if(s[i]==s[j]){
if(i+1==j)dp[i,j]=2;
elsedp[i,j]=dp[i+1,j-1]+2;
}
else{
// Otherwise, take the maximum length
// from either excluding i or j
dp[i,j]=Math.Max(dp[i+1,j],dp[i,j-1]);
}
}
}
// The final answer is stored in dp[0][n-1]
returndp[0,n-1];
}
staticvoidMain(string[]args){
strings="bbabcbcab";
Console.WriteLine(longestPalinSubseq(s));
}
}
JavaScript
// JavaScript program to find the lps
// Function to find the LPS
functionlongestPalinSubseq(s){
constn=s.length;
// Create a DP table
constdp=Array.from({length:n},
()=>Array(n).fill(0));
// Build the DP table for all the substrings
for(leti=n-1;i>=0;i--){
for(letj=i;j<n;j++){
// If there is only one character
if(i===j){
dp[i][j]=1;
continue;
}
// If characters at position i and j are the same
if(s[i]===s[j]){
if(i+1===j)dp[i][j]=2;
elsedp[i][j]=dp[i+1][j-1]+2;
}
else{
// Otherwise, take the maximum length
// from either excluding i or j
dp[i][j]=Math.max(dp[i+1][j],dp[i][j-1]);
}
}
}
// The final answer is stored in dp[0][n-1]
returndp[0][n-1];
}
consts="bbabcbcab";
console.log(longestPalinSubseq(s));

Output
7

[Expected Approach] Using Tabulation - O(n^2) Time and O(n) Space

In the above approach, for calculating the LPS of substrings starting from index i, only the LPS of substrings starting from index i+1 are required. Thus instead of creating 2d array, idea is to create two arrays of size, curr[] and prev[], where curr[j] stores the lps of substring from s[i] to s[j], while prev[j] stores the lps of substring from s[i+1] to s[j]. Else everything will be similar to above approach.

C++
// C++ program to find longest
// palindromic subsequence 
#include<bits/stdc++.h>
usingnamespacestd;
// Function to find the length of the lps
intlongestPalinSubseq(conststring&s){
intn=s.size();
// Create two vectors: one for the current state (dp)
// and one for the previous state (dpPrev)
vector<int>curr(n),prev(n);
// Loop through the string in reverse (starting from the end)
for(inti=n-1;i>=0;--i){
// Initialize the current state of dp
curr[i]=1;
// Loop through the characters ahead of i
for(intj=i+1;j<n;++j){
// If the characters at i and j are the same
if(s[i]==s[j]){
// Add 2 to the length of the palindrome between them
curr[j]=prev[j-1]+2;
}
else{
// Take the maximum between excluding either i or j
curr[j]=max(prev[j],curr[j-1]);
}
}
// Update previous to the current state of dp
prev=curr;
}
returncurr[n-1];
}
intmain(){
strings="bbabcbcab";
cout<<longestPalinSubseq(s);
return0;
}
Java
// Java program to find longest
// palindromic subsequence 
importjava.util.*;
// Java program to find the length of the lps
class GfG{
// Function to find the length of the lps
staticintlongestPalinSubseq(Strings){
intn=s.length();
// Create two arrays: one for the current state (dp)
// and one for the previous state (dpPrev)
int[]curr=newint[n];
int[]prev=newint[n];
// Loop through the string in reverse (starting from the end)
for(inti=n-1;i>=0;--i){
// Initialize the current state of dp
curr[i]=1;
// Loop through the characters ahead of i
for(intj=i+1;j<n;++j){
// If the characters at i and j are the same
if(s.charAt(i)==s.charAt(j)){
// Add 2 to the length of the palindrome between them
curr[j]=prev[j-1]+2;
}else{
// Take the maximum between excluding either i or j
curr[j]=Math.max(prev[j],curr[j-1]);
}
}
// Update previous to the current state of dp
prev=curr.clone();
}
returncurr[n-1];
}
publicstaticvoidmain(String[]args){
Strings="bbabcbcab";
System.out.println(longestPalinSubseq(s));
}
}
Python
# Python program to find the length of the lps
# Function to find the length of the lps
def longestPalinSubseq(s):
 n = len(s)
 # Create two arrays: one for the current state (dp)
 # and one for the previous state (dpPrev)
 curr = [0] * n
 prev = [0] * n
 # Loop through the string in reverse (starting from the end)
 for i in range(n - 1, -1, -1):
 # Initialize the current state of dp
 curr[i] = 1
 # Loop through the characters ahead of i
 for j in range(i + 1, n):
 # If the characters at i and j are the same
 if s[i] == s[j]:
 # Add 2 to the length of the palindrome between them
 curr[j] = prev[j - 1] + 2
 else:
 # Take the maximum between excluding either i or j
 curr[j] = max(prev[j], curr[j - 1])
 # Update previous to the current state of dp
 prev = curr[:]
 return curr[n - 1]
if __name__ == "__main__":
 s = "bbabcbcab"
 print(longestPalinSubseq(s))
C#
// C# program to find longest
// palindromic subsequence 
usingSystem;
// C# program to find the length of the lps
classGfG{
// Function to find the length of the lps
staticintlongestPalinSubseq(strings){
intn=s.Length;
// Create two arrays: one for the current state (dp)
// and one for the previous state (dpPrev)
int[]curr=newint[n];
int[]prev=newint[n];
// Loop through the string in reverse (starting from the end)
for(inti=n-1;i>=0;--i){
// Initialize the current state of dp
curr[i]=1;
// Loop through the characters ahead of i
for(intj=i+1;j<n;++j){
// If the characters at i and j are the same
if(s[i]==s[j]){
// Add 2 to the length of the palindrome between them
curr[j]=prev[j-1]+2;
}else{
// Take the maximum between excluding either i or j
curr[j]=Math.Max(prev[j],curr[j-1]);
}
}
// Update previous to the current state of dp
Array.Copy(curr,prev,n);
}
returncurr[n-1];
}
staticvoidMain(string[]args){
strings="bbabcbcab";
Console.WriteLine(longestPalinSubseq(s));
}
}
JavaScript
// JavaScript program to find the length of the lps
// Function to find the length of the lps
functionlongestPalinSubseq(s){
constn=s.length;
// Create two arrays: one for the current state (dp)
// and one for the previous state (dpPrev)
letcurr=newArray(n).fill(0);
letprev=newArray(n).fill(0);
// Loop through the string in reverse (starting from the end)
for(leti=n-1;i>=0;--i){
// Initialize the current state of dp
curr[i]=1;
// Loop through the characters ahead of i
for(letj=i+1;j<n;++j){
// If the characters at i and j are the same
if(s[i]===s[j]){
// Add 2 to the length of the palindrome between them
curr[j]=prev[j-1]+2;
}else{
// Take the maximum between excluding either i or j
curr[j]=Math.max(prev[j],curr[j-1]);
}
}
// Update previous to the current state of dp
prev=[...curr];
}
returncurr[n-1];
}
consts="bbabcbcab";
console.log(longestPalinSubseq(s));

Output
7

[Alternate Approach] Using Longest Common Subsequence - O(n^2) Time and O(n) Space

The idea is to reverse the given string s and find the length of the longest common subsequence of original and reversed string.



[フレーム]
Longest Palindromic Subsequence
Improve
Article Tags :

Explore

Improvement
Suggest Changes
Help us improve. Share your suggestions to enhance the article. Contribute your expertise and make a difference in the GeeksforGeeks portal.
geeksforgeeks-suggest-icon
Create Improvement
Enhance the article with your expertise. Contribute to the GeeksforGeeks community and help create better learning resources for all.
geeksforgeeks-improvement-icon
Suggest Changes
min 4 words, max Words Limit:1000

Thank You!

Your suggestions are valuable to us.

AltStyle によって変換されたページ (->オリジナル) /