Given a string s, find out if the string is k-Palindrome or not. A k-palindrome string transforms into a palindrome on removing at most k characters from it.
Examples :
Input: s = "abcdecba", k = 1
Output: true
Explanation: String can become palindrome by removing 1 character i.e. either d or e.Input: s = "abcdeca", k = 2
Output: true
Explanation: Can become palindrome by removing 2 characters b and e.Input: s= "acdcb", k = 1
Output: false
Explanation: String can not become palindrome by removing only one character.
Table of Content
[Naive Approach] Edit Distance Recursion and Reverse – O(2 ^ n) Time and O(n) Space
If we carefully analyze the problem, it is basically a variation of Edit Distance. We can modify the Edit Distance problem to consider the given string and its reverse as input and the only operation allowed is deletion. To form a palindrome, the same character has to deleted from both s and its reverse. Therefore, for a string to be k-palindrome, total deletions <= 2*k should hold true.
- If the last characters of the two strings are same, we ignore last characters and get count for remaining strings. So we recur for lengths m-1 and n-1 where m is length of s1 and n is length of s2.
- If the last characters are not same, remove last char from s1 and recur for m-1 and n. Then remove last char from s2 and recur for m and n-1. We take the minimum of two operations and add 1 to it.
#include <iostream>
#include <string>
#include <algorithm>
using namespace std;
// find if given string is K-Palindrome or not
int isKPalRec(string s1, string s2, int m, int n)
{
// If first string is empty, the only option is to
// remove all characters of second string
if (m == 0) return n;
// If second string is empty, the only option is to
// remove all characters of first string
if (n == 0) return m;
// If last characters of two strings are same, ignore
// last characters and get count for remaining strings.
if (s1[m-1] == s2[n-1])
return isKPalRec(s1, s2, m-1, n-1);
// If last characters are not same,
// 1. Remove last char from s1 and recur for m-1 and n
// 2. Remove last char from s2 and recur for m and n-1
// Take minimum of above two operations
return 1 + min(isKPalRec(s1, s2, m-1, n), // Remove from s1
isKPalRec(s1, s2, m, n-1)); // Remove from s2
}
// Returns true if s is k palindrome.
bool kPalindrome(string &s, int k)
{
string s1 = s;
reverse(s1.begin(), s1.end());
int n = s.length();
return (isKPalRec(s, s1, n, n) <= k * 2);
}
// Driver program
int main()
{
string s = "acdcb";
int k = 2;
kPalindrome(s, k) ? cout << "True" : cout << "False";
return 0;
}
import java.util.*;
class GFG {
// find if given string is K-Palindrome or not
static int isKPalRec(String s1, String s2, int m, int n)
{
// If first string is empty, the only option is to
// remove all characters of second string
if (m == 0) return n;
// If second string is empty, the only option is to
// remove all characters of first string
if (n == 0) return m;
// If last characters of two strings are same, ignore
// last characters and get count for remaining strings.
if (s1.charAt(m - 1) == s2.charAt(n - 1))
return isKPalRec(s1, s2, m - 1, n - 1);
// If last characters are not same,
// 1. Remove last char from s1 and recur for m-1 and n
// 2. Remove last char from s2 and recur for m and n-1
// Take minimum of above two operations
return 1 + Math.min(isKPalRec(s1, s2, m - 1, n), // Remove from s1
isKPalRec(s1, s2, m, n - 1)); // Remove from s2
}
// Returns true if s is k palindrome.
static boolean kPalindrome(String s, int k)
{
String s1 = new StringBuilder(s).reverse().toString();
int n = s.length();
return (isKPalRec(s, s1, n, n) <= k * 2);
}
// Driver program
public static void main(String[] args)
{
String s = "acdcb";
int k = 2;
System.out.println(kPalindrome(s, k) ? "Yes" : "No");
}
}
# find if given string is K-Palindrome or not
def isKPalRec(s1, s2, m, n):
# If first string is empty, the only option is to
# remove all characters of second string
if m == 0:
return n
# If second string is empty, the only option is to
# remove all characters of first string
if n == 0:
return m
# If last characters of two strings are same, ignore
# last characters and get count for remaining strings.
if s1[m - 1] == s2[n - 1]:
return isKPalRec(s1, s2, m - 1, n - 1)
# If last characters are not same,
# 1. Remove last char from s1 and recur for m-1 and n
# 2. Remove last char from s2 and recur for m and n-1
# Take minimum of above two operations
return 1 + min(isKPalRec(s1, s2, m - 1, n), # Remove from s1
isKPalRec(s1, s2, m, n - 1)) # Remove from s2
# Returns true if s is k palindrome.
def kPalindrome(s, k):
s1 = s[::-1]
n = len(s)
return isKPalRec(s, s1, n, n) <= k * 2
# Driver program
s = "acdcb"
k = 2
print("Yes" if kPalindrome(s, k) else "No")
using System;
class GFG {
// find if given string is K-Palindrome or not
static int isKPalRec(string s1, string s2, int m, int n)
{
// If first string is empty, the only option is to
// remove all characters of second string
if (m == 0) return n;
// If second string is empty, the only option is to
// remove all characters of first string
if (n == 0) return m;
// If last characters of two strings are same, ignore
// last characters and get count for remaining strings.
if (s1[m - 1] == s2[n - 1])
return isKPalRec(s1, s2, m - 1, n - 1);
// If last characters are not same,
// 1. Remove last char from s1 and recur for m-1 and n
// 2. Remove last char from s2 and recur for m and n-1
// Take minimum of above two operations
return 1 + Math.Min(isKPalRec(s1, s2, m - 1, n), // Remove from s1
isKPalRec(s1, s2, m, n - 1)); // Remove from s2
}
// Returns true if s is k palindrome.
static bool kPalindrome(string s, int k)
{
char[] arr = s.ToCharArray();
Array.Reverse(arr);
string s1 = new string(arr);
int n = s.Length;
return (isKPalRec(s, s1, n, n) <= k * 2);
}
// Driver program
static void Main()
{
string s = "acdcb";
int k = 2;
Console.WriteLine(kPalindrome(s, k) ? "Yes" : "No");
}
}
// find if given string is K-Palindrome or not
function isKPalRec(s1, s2, m, n)
{
// If first string is empty, the only option is to
// remove all characters of second string
if (m == 0) return n;
// If second string is empty, the only option is to
// remove all characters of first string
if (n == 0) return m;
// If last characters of two strings are same, ignore
// last characters and get count for remaining strings.
if (s1[m - 1] == s2[n - 1])
return isKPalRec(s1, s2, m - 1, n - 1);
// If last characters are not same,
// 1. Remove last char from s1 and recur for m-1 and n
// 2. Remove last char from s2 and recur for m and n-1
// Take minimum of above two operations
return 1 + Math.min(isKPalRec(s1, s2, m - 1, n), // Remove from s1
isKPalRec(s1, s2, m, n - 1)); // Remove from s2
}
// Returns true if s is k palindrome.
function kPalindrome(s, k)
{
let s1 = s.split('').reverse().join('');
let n = s.length;
return (isKPalRec(s, s1, n, n) <= k * 2);
}
// Driver program
let s = "acdcb";
let k = 2;
console.log(kPalindrome(s, k) ? "Yes" : "No");
Output
True
[Expected Approach 1] Edit Distance Bottom Up and Reverse – O(n²) Time and O(n²) Space
We mainly optimize the above recursive solution using a dp table of size (m+1)x(n+1) where dp[i][j] represents total deletions to match prefixes of lengths i and j. At the end, we return return true if dp[m][n] <= 2*k.
- Reverse the original string.
- Build a DP table where each cell dp[i][j] stores minimum deletions required to match prefixes of lengths i and j.
- If characters match, move diagonally; otherwise take minimum deletion operation
- Check if final deletions required are less than or equal to
2 * k
#include <iostream>
#include <string>
#include <algorithm>
using namespace std;
// find if given string is K-Palindrome or not
int isKPalDP(string s1, string s2, int m, int n)
{
// Create a table to store results of subproblems
int dp[m + 1][n + 1];
// Fill dp[][] in bottom up manner
for (int i = 0; i <= m; i++)
{
for (int j = 0; j <= n; j++)
{
// If first string is empty, only option is to
// remove all characters of second string
if (i == 0)
dp[i][j] = j; // Min. operations = j
// If second string is empty, only option is to
// remove all characters of first string
else if (j == 0)
dp[i][j] = i; // Min. operations = i
// If last characters are same, ignore last character
// and recur for remaining string
else if (s1[i - 1] == s2[j - 1])
dp[i][j] = dp[i - 1][j - 1];
// If last character are different, remove it
// and find minimum
else
dp[i][j] = 1 + min(dp[i - 1][j], // Remove from s1
dp[i][j - 1]); // Remove from s2
}
}
return dp[m][n];
}
// Returns true if s is k palindrome.
bool kPalindrome(string &s, int k)
{
string s1 = s;
reverse(s1.begin(), s1.end());
int n = s.length();
return (isKPalDP(s, s1, n, n) <= k * 2);
}
// Driver program
int main()
{
string s = "acdcb";
int k = 2;
kPalindrome(s, k) ? cout << "True" : cout << "False";
return 0;
}
import java.util.*;
class GFG {
// find if given string is K-Palindrome or not
static int isKPalDP(String s1, String s2, int m, int n)
{
// Create a table to store results of subproblems
int[][] dp = new int[m + 1][n + 1];
// Fill dp[][] in bottom up manner
for (int i = 0; i <= m; i++)
{
for (int j = 0; j <= n; j++)
{
// If first string is empty, only option is to
// remove all characters of second string
if (i == 0)
dp[i][j] = j; // Min. operations = j
// If second string is empty, only option is to
// remove all characters of first string
else if (j == 0)
dp[i][j] = i; // Min. operations = i
// If last characters are same, ignore last character
// and recur for remaining string
else if (s1.charAt(i - 1) == s2.charAt(j - 1))
dp[i][j] = dp[i - 1][j - 1];
// If last character are different, remove it
// and find minimum
else
dp[i][j] = 1 + Math.min(dp[i - 1][j], // Remove from s1
dp[i][j - 1]); // Remove from s2
}
}
return dp[m][n];
}
// Returns true if s is k palindrome.
static boolean kPalindrome(String s, int k)
{
String s1 = s;
s1 = new StringBuilder(s1).reverse().toString();
int n = s.length();
return (isKPalDP(s, s1, n, n) <= k * 2);
}
// Driver program
public static void main(String[] args)
{
String s = "acdcb";
int k = 2;
System.out.println(kPalindrome(s, k) ? "True" : "False");
}
}
# find if given string is K-Palindrome or not
def isKPalDP(s1, s2, m, n):
# Create a table to store results of subproblems
dp = [[0 for j in range(n + 1)] for i in range(m + 1)]
# Fill dp[][] in bottom up manner
for i in range(m + 1):
for j in range(n + 1):
# If first string is empty, only option is to
# remove all characters of second string
if i == 0:
dp[i][j] = j # Min. operations = j
# If second string is empty, only option is to
# remove all characters of first string
elif j == 0:
dp[i][j] = i # Min. operations = i
# If last characters are same, ignore last character
# and recur for remaining string
elif s1[i - 1] == s2[j - 1]:
dp[i][j] = dp[i - 1][j - 1]
# If last character are different, remove it
# and find minimum
else:
dp[i][j] = 1 + min(dp[i - 1][j], # Remove from s1
dp[i][j - 1]) # Remove from s2
return dp[m][n]
# Returns true if s is k palindrome.
def kPalindrome(s, k):
s1 = s
s1 = s1[::-1]
n = len(s)
return isKPalDP(s, s1, n, n) <= k * 2
# Driver program
s = "acdcb"
k = 2
print("True" if kPalindrome(s, k) else "False")
using System;
class GFG {
// find if given string is K-Palindrome or not
static int isKPalDP(string s1, string s2, int m, int n)
{
// Create a table to store results of subproblems
int[,] dp = new int[m + 1, n + 1];
// Fill dp[][] in bottom up manner
for (int i = 0; i <= m; i++)
{
for (int j = 0; j <= n; j++)
{
// If first string is empty, only option is to
// remove all characters of second string
if (i == 0)
dp[i, j] = j; // Min. operations = j
// If second string is empty, only option is to
// remove all characters of first string
else if (j == 0)
dp[i, j] = i; // Min. operations = i
// If last characters are same, ignore last character
// and recur for remaining string
else if (s1[i - 1] == s2[j - 1])
dp[i, j] = dp[i - 1, j - 1];
// If last character are different, remove it
// and find minimum
else
dp[i, j] = 1 + Math.Min(dp[i - 1, j], // Remove from s1
dp[i, j - 1]); // Remove from s2
}
}
return dp[m, n];
}
// Returns true if s is k palindrome.
static bool kPalindrome(string s, int k)
{
string s1 = s;
char[] arr = s1.ToCharArray();
Array.Reverse(arr);
s1 = new string(arr);
int n = s.Length;
return (isKPalDP(s, s1, n, n) <= k * 2);
}
// Driver program
static void Main()
{
string s = "acdcb";
int k = 2;
Console.WriteLine(kPalindrome(s, k) ? "True" : "False");
}
}
// find if given string is K-Palindrome or not
function isKPalDP(s1, s2, m, n)
{
// Create a table to store results of subproblems
let dp = Array.from({ length: m + 1 }, () =>
Array(n + 1).fill(0)
);
// Fill dp[][] in bottom up manner
for (let i = 0; i <= m; i++)
{
for (let j = 0; j <= n; j++)
{
// If first string is empty, only option is to
// remove all characters of second string
if (i == 0)
dp[i][j] = j; // Min. operations = j
// If second string is empty, only option is to
// remove all characters of first string
else if (j == 0)
dp[i][j] = i; // Min. operations = i
// If last characters are same, ignore last character
// and recur for remaining string
else if (s1[i - 1] == s2[j - 1])
dp[i][j] = dp[i - 1][j - 1];
// If last character are different, remove it
// and find minimum
else
dp[i][j] = 1 + Math.min(dp[i - 1][j], // Remove from s1
dp[i][j - 1]); // Remove from s2
}
}
return dp[m][n];
}
// Returns true if s is k palindrome.
function kPalindrome(s, k)
{
let s1 = s;
s1 = s1.split('').reverse().join('');
let n = s.length;
return (isKPalDP(s, s1, n, n) <= k * 2);
}
// Driver program
let s = "acdcb";
let k = 2;
console.log(kPalindrome(s, k) ? "True" : "False");
Output
True
[Efficient Approach] Using Longest Palindromic Subsequence (LPS) – O(n²) Time and O(n²) Space
The idea to find Longest Palindromic Subsequence (LPS) and subtract its length from total string length to find the number of deletions. We compute LPS using LCS between the string and its reverse. If the number of characters not included in the LPS is at most
k, then the string can be converted into a palindrome by removing at mostkcharacters. Thus, we only need to check whethern - LPS <= k.
- Reverse the original string and compute LCS between both strings
- Use dynamic programming to build the LCS table
- The LCS length represents the longest palindromic subsequence
- If
n - LPS <= k, return true otherwise false
#include <iostream>
#include <string>
#include <algorithm>
using namespace std;
/* Returns length of LCS for s1 and s2 */
int lcs(string s1, string s2, int m, int n)
{
int dp[m + 1][n + 1];
/* Following steps build dp[m+1][n+1] in bottom up
fashion. Note that dp[i][j] contains length of
LCS of a1 and s2 */
for (int i = 0; i <= m; i++)
{
for (int j = 0; j <= n; j++)
{
if (i == 0 || j == 0)
dp[i][j] = 0;
else if (s1[i - 1] == s2[j - 1])
dp[i][j] = dp[i - 1][j - 1] + 1;
else
dp[i][j] = max(dp[i - 1][j],
dp[i][j - 1]);
}
}
// dp[m][n] contains length of LCS for s1 and s2
return dp[m][n];
}
// find if given string is K-Palindrome or not
bool kPalindrome(string &s, int k)
{
int n = s.length();
// Find reverse of string
string s1 = s;
reverse(s1.begin(), s1.end());
// find longest palindromic subsequence of
// given string
int lps = lcs(s, s1, n, n);
// If the difference between longest palindromic
// subsequence and the original string is less
// than equal to k, then the string is k-palindrome
return (n - lps <= k);
}
// Driver program
int main()
{
string s = "abcdeca";
int k = 2;
kPalindrome(s, k) ? cout << "True" : cout << "False";
return 0;
}
import java.util.*;
class GFG {
/* Returns length of LCS for s1 and s2 */
static int lcs(String s1, String s2, int m, int n)
{
int[][] dp = new int[m + 1][n + 1];
/* Following steps build dp[m+1][n+1] in bottom up
fashion. Note that dp[i][j] contains length of
LCS of a1 and s2 */
for (int i = 0; i <= m; i++)
{
for (int j = 0; j <= n; j++)
{
if (i == 0 || j == 0)
dp[i][j] = 0;
else if (s1.charAt(i - 1) == s2.charAt(j - 1))
dp[i][j] = dp[i - 1][j - 1] + 1;
else
dp[i][j] = Math.max(dp[i - 1][j],
dp[i][j - 1]);
}
}
// dp[m][n] contains length of LCS for s1 and s2
return dp[m][n];
}
// find if given string is K-Palindrome or not
static boolean kPalindrome(String s, int k)
{
int n = s.length();
// Find reverse of string
String s1 = s;
s1 = new StringBuilder(s1).reverse().toString();
// find longest palindromic subsequence of
// given string
int lps = lcs(s, s1, n, n);
// If the difference between longest palindromic
// subsequence and the original string is less
// than equal to k, then the string is k-palindrome
return (n - lps <= k);
}
// Driver program
public static void main(String[] args)
{
String s = "abcdeca";
int k = 2;
System.out.println(kPalindrome(s, k) ? "True" : "False");
}
}
# Returns length of LCS for s1 and s2
def lcs(s1, s2, m, n):
dp = [[0 for j in range(n + 1)] for i in range(m + 1)]
# Following steps build dp[m+1][n+1] in bottom up
# fashion. Note that dp[i][j] contains length of
# LCS of a1 and s2
for i in range(m + 1):
for j in range(n + 1):
if i == 0 or j == 0:
dp[i][j] = 0
elif s1[i - 1] == s2[j - 1]:
dp[i][j] = dp[i - 1][j - 1] + 1
else:
dp[i][j] = max(dp[i - 1][j],
dp[i][j - 1])
# dp[m][n] contains length of LCS for s1 and s2
return dp[m][n]
# find if given string is K-Palindrome or not
def kPalindrome(s, k):
n = len(s)
# Find reverse of string
s1 = s
s1 = s1[::-1]
# find longest palindromic subsequence of
# given string
lps = lcs(s, s1, n, n)
# If the difference between longest palindromic
# subsequence and the original string is less
# than equal to k, then the string is k-palindrome
return (n - lps <= k)
# Driver program
s = "abcdeca"
k = 2
print("True" if kPalindrome(s, k) else "False")
using System;
class GFG {
/* Returns length of LCS for s1 and s2 */
static int lcs(string s1, string s2, int m, int n)
{
int[,] dp = new int[m + 1, n + 1];
/* Following steps build dp[m+1][n+1] in bottom up
fashion. Note that dp[i][j] contains length of
LCS of a1 and s2 */
for (int i = 0; i <= m; i++)
{
for (int j = 0; j <= n; j++)
{
if (i == 0 || j == 0)
dp[i, j] = 0;
else if (s1[i - 1] == s2[j - 1])
dp[i, j] = dp[i - 1, j - 1] + 1;
else
dp[i, j] = Math.Max(dp[i - 1, j],
dp[i, j - 1]);
}
}
// dp[m][n] contains length of LCS for s1 and s2
return dp[m, n];
}
// find if given string is K-Palindrome or not
static bool kPalindrome(string s, int k)
{
int n = s.Length;
// Find reverse of string
string s1 = s;
char[] arr = s1.ToCharArray();
Array.Reverse(arr);
s1 = new string(arr);
// find longest palindromic subsequence of
// given string
int lps = lcs(s, s1, n, n);
// If the difference between longest palindromic
// subsequence and the original string is less
// than equal to k, then the string is k-palindrome
return (n - lps <= k);
}
// Driver program
static void Main()
{
string s = "abcdeca";
int k = 2;
Console.WriteLine(kPalindrome(s, k) ? "True" : "False");
}
}
/* Returns length of LCS for s1 and s2 */
function lcs(s1, s2, m, n)
{
let dp = Array.from({ length: m + 1 }, () =>
Array(n + 1).fill(0)
);
/* Following steps build dp[m+1][n+1] in bottom up
fashion. Note that dp[i][j] contains length of
LCS of a1 and s2 */
for (let i = 0; i <= m; i++)
{
for (let j = 0; j <= n; j++)
{
if (i == 0 || j == 0)
dp[i][j] = 0;
else if (s1[i - 1] == s2[j - 1])
dp[i][j] = dp[i - 1][j - 1] + 1;
else
dp[i][j] = Math.max(dp[i - 1][j],
dp[i][j - 1]);
}
}
// dp[m][n] contains length of LCS for s1 and s2
return dp[m][n];
}
// find if given string is K-Palindrome or not
function kPalindrome(s, k)
{
let n = s.length;
// Find reverse of string
let s1 = s;
s1 = s1.split('').reverse().join('');
// find longest palindromic subsequence of
// given string
let lps = lcs(s, s1, n, n);
// If the difference between longest palindromic
// subsequence and the original string is less
// than equal to k, then the string is k-palindrome
return (n - lps <= k);
}
// Driver program
let s = "abcdeca";
let k = 2;
console.log(kPalindrome(s, k) ? "True" : "False");
Output
True