| Difficulty | Medium | ||
|---|---|---|---|
| Source | 160 Days of Problem Solving | ||
| Tags |
|
The problem can be found at the following link: Question Link
Given a string s, return the length of the longest palindromic subsequence.
A subsequence is a sequence derived from the given sequence by deleting some or no elements without changing the order of the remaining elements.
A palindromic subsequence reads the same forwards and backwards.
s = "bbabcbcab"
7
The longest palindromic subsequence is "babcbab", which has a length of 7.
s = "abcd"
1
The longest palindromic subsequence is any single character, which has a length of 1.
s = "agbdba"
5
The longest palindromic subsequence is "abdba", which has a length of 5.
$1 \leq s.size() \leq 1000$ - The string contains only lowercase letters.
- Create a 2D DP table, where
dp[i][j]stores the length of the longest palindromic subsequence in substrings[i...j]. - Initialize diagonal elements (
dp[i][i]) to 1, since a single character is always a palindrome of length 1. - Iterate over substrings of increasing lengths.
- For each substring
s[i...j]:- If
s[i] == s[j], the length extends by 2 (both characters can form a palindrome around the inner subsequences[i+1...j-1]). - Otherwise, take the maximum palindromic subsequence length by either excluding
s[i]or excludings[j].
- If
- Final answer is stored in
dp[0][n-1]— the longest palindromic subsequence in the entire string.
-
Expected Time Complexity:
$O(N^2)$ , as we fill a 2D DP table for all substrings, and each cell is filled in constant time. -
Expected Auxiliary Space Complexity:
$O(N^2)$ , for storing the DP table, which tracks the longest palindromic subsequence length for each substring.
class Solution {
public:
int longestPalinSubseq(string &s) {
int n = s.size();
vector<vector<int>> dp(n, vector<int>(n, 0));
for (int i = n - 1; i >= 0; i--) {
dp[i][i] = 1;
for (int j = i + 1; j < n; j++) {
if (s[i] == s[j])
dp[i][j] = 2 + dp[i + 1][j - 1];
else
dp[i][j] = max(dp[i + 1][j], dp[i][j - 1]);
}
}
return dp[0][n - 1];
}
};- We only need the current and previous rows, so the 2D table can be reduced to two 1D arrays.
- Iterate over
i(backwards) andj(forwards), and fill only the current row using the previous row. - This reduces space from O(N²) to O(N).
class Solution {
public:
int longestPalinSubseq(string &s) {
int n = s.size();
vector<int> prev(n + 1, 0), curr(n + 1, 0);
for (int i = 1; i <= n; ++i) {
for (int j = 1; j <= n; ++j) {
if (s[i - 1] == s[n - j])
curr[j] = 1 + prev[j - 1];
else
curr[j] = max(prev[j], curr[j - 1]);
}
swap(prev, curr);
}
return prev[n];
}
};- Use recursive DFS with memoization.
- If characters match, extend the palindrome.
- Otherwise, check both possibilities (exclude either character).
- Cache results to avoid redundant work.
class Solution {
public:
int helper(string &s, int i, int j, vector<vector<int>> &dp) {
if (i > j) return 0;
if (i == j) return 1;
if (dp[i][j] != -1) return dp[i][j];
if (s[i] == s[j])
return dp[i][j] = 2 + helper(s, i + 1, j - 1, dp);
return dp[i][j] = max(helper(s, i + 1, j, dp), helper(s, i, j - 1, dp));
}
int longestPalinSubseq(string &s) {
int n = s.size();
vector<vector<int>> dp(n, vector<int>(n, -1));
return helper(s, 0, n - 1, dp);
}
};| Approach | ⏱️ Time Complexity | 🗂️ Space Complexity | ✅ Pros | |
|---|---|---|---|---|
| 2D DP Table | 🟡 O(N²) | 🔴 O(N²) | Simple & intuitive | High space usage |
| Space Optimized 1D DP | 🟡 O(N²) | 🟢 O(N) | Lower space | Slightly trickier to implement |
| Recursive + Memoization | 🟡 O(N²) | 🔴 O(N²) | Natural recursive logic | Recursion overhead |
- ✅ For balanced space and time: Use Space Optimized 1D DP.
- ✅ For simplicity and clarity: Use 2D DP Table.
- ✅ For recursive enthusiasts: Use Recursive + Memoization.
class Solution {
public int longestPalinSubseq(String s) {
int n = s.length();
int[][] dp = new int[n][n];
for (int i = n - 1; i >= 0; i--) {
dp[i][i] = 1;
for (int j = i + 1; j < n; j++) {
if (s.charAt(i) == s.charAt(j))
dp[i][j] = 2 + dp[i + 1][j - 1];
else
dp[i][j] = Math.max(dp[i + 1][j], dp[i][j - 1]);
}
}
return dp[0][n - 1];
}
}class Solution:
def longestPalinSubseq(self, s):
n = len(s)
dp = [[0] * n for _ in range(n)]
for i in range(n - 1, -1, -1):
dp[i][i] = 1
for j in range(i + 1, n):
if s[i] == s[j]:
dp[i][j] = 2 + dp[i + 1][j - 1]
else:
dp[i][j] = max(dp[i + 1][j], dp[i][j - 1])
return dp[0][n - 1]For discussions, questions, or doubts related to this solution, feel free to connect on LinkedIn: Any Questions. Let’s make this learning journey more collaborative!
⭐ If you find this helpful, please give this repository a star! ⭐