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: Yes
Explanation: String can become palindrome by removing 1 character i.e. either d or e.
Input: S = “abcdeca”, K = 2
Output: Yes
Explanation: Can become palindrome by removing 2 characters b and e.
Input: S= “acdcb”, K = 1
Output: No
Explanation: String can not become palindrome by removing only one character.
If we carefully analyze the problem, the task is to transform the given string into its reverse by removing at most K characters from it. The problem 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. Since the given string is compared with its reverse, we will do at most N deletions from the first string and N deletions from the second string to make them equal. Therefore, for a string to be k-palindrome, 2*N <= 2*K should hold true.
Below are the detailed steps of the algorithm:
Process all characters one by one starting from either the left or right sides of both strings. Let us traverse from the right corner, there are two possibilities for every pair of characters being traversed.
- 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 str1 and n is length of str2.
- If the last characters are not same, we consider removing operation on last character of first string and last character of the second string, recursively compute minimum cost for the operations and take minimum of two values.
- Remove last char from str1: Recur for m-1 and n.
- Remove last char from str2: Recur for m and n-1.
Below is the Naive recursive implementation of the above approach:
C++
#include<bits/stdc++.h>
using namespace std;
int isKPalRec(string str1, string str2, int m, int n)
{
if (m == 0) return n;
if (n == 0) return m;
if (str1[m-1] == str2[n-1])
return isKPalRec(str1, str2, m-1, n-1);
return 1 + min(isKPalRec(str1, str2, m-1, n),
isKPalRec(str1, str2, m, n-1));
}
bool isKPal(string str, int k)
{
string revStr = str;
reverse(revStr.begin(), revStr.end());
int len = str.length();
return (isKPalRec(str, revStr, len, len) <= k*2);
}
int main()
{
string str = "acdcb" ;
int k = 2;
isKPal(str, k)? cout << "Yes" : cout << "No" ;
return 0;
}
|
Java
import java.util.*;
import java.io.*;
class GFG
{
static int isKPalRec(String str1,
String str2, int m, int n)
{
if (m == 0 )
{
return n;
}
if (n == 0 )
{
return m;
}
if (str1.charAt(m - 1 ) ==
str2.charAt(n - 1 ))
{
return isKPalRec(str1, str2,
m - 1 , n - 1 );
}
return 1 + Math.min(isKPalRec(str1, str2, m - 1 , n),
isKPalRec(str1, str2, m, n - 1 ));
}
static boolean isKPal(String str, int k)
{
String revStr = str;
revStr = reverse(revStr);
int len = str.length();
return (isKPalRec(str, revStr, len, len) <= k * 2 );
}
static String reverse(String input)
{
char [] temparray = input.toCharArray();
int left, right = 0 ;
right = temparray.length - 1 ;
for (left = 0 ; left < right; left++, right--)
{
char temp = temparray[left];
temparray[left] = temparray[right];
temparray[right] = temp;
}
return String.valueOf(temparray);
}
public static void main(String[] args)
{
String str = "acdcb" ;
int k = 2 ;
if (isKPal(str, k))
{
System.out.println( "Yes" );
}
else
{
System.out.println( "No" );
}
}
}
|
Python3
def isKPalRec(str1, str2, m, n):
if not m: return n
if not n: return m
if str1[m - 1 ] = = str2[n - 1 ]:
return isKPalRec(str1, str2, m - 1 , n - 1 )
res = 1 + min (isKPalRec(str1, str2, m - 1 , n),
(isKPalRec(str1, str2, m, n - 1 )))
return res
def isKPal(string, k):
revStr = string[:: - 1 ]
l = len (string)
return (isKPalRec(string, revStr, l, l) < = k * 2 )
string = "acdcb"
k = 2
print ( "Yes" if isKPal(string, k) else "No" )
|
C#
using System;
class GFG
{
static int isKPalRec(String str1,
String str2, int m, int n)
{
if (m == 0)
{
return n;
}
if (n == 0)
{
return m;
}
if (str1[m - 1] ==
str2[n - 1])
{
return isKPalRec(str1, str2,
m - 1, n - 1);
}
return 1 + Math.Min(isKPalRec(str1, str2, m - 1, n),
isKPalRec(str1, str2, m, n - 1));
}
static bool isKPal(String str, int k)
{
String revStr = str;
revStr = reverse(revStr);
int len = str.Length;
return (isKPalRec(str, revStr, len, len) <= k * 2);
}
static String reverse(String input)
{
char [] temparray = input.ToCharArray();
int left, right = 0;
right = temparray.Length - 1;
for (left = 0; left < right; left++, right--)
{
char temp = temparray[left];
temparray[left] = temparray[right];
temparray[right] = temp;
}
return String.Join( "" ,temparray);
}
public static void Main(String[] args)
{
String str = "acdcb" ;
int k = 2;
if (isKPal(str, k))
{
Console.WriteLine( "Yes" );
}
else
{
Console.WriteLine( "No" );
}
}
}
|
Javascript
<script>
function isKPalRec( str1, str2 , m , n)
{
if (m == 0) {
return n;
}
if (n == 0) {
return m;
}
if (str1.charAt(m - 1) == str2[n - 1]) {
return isKPalRec(str1, str2, m - 1, n - 1);
}
return 1 + Math.min(isKPalRec(str1, str2, m - 1, n),
isKPalRec(str1, str2, m, n - 1));
}
function isKPal( str , k) {
var revStr = str;
revStr = reverse(revStr);
var len = str.length;
return (isKPalRec(str, revStr, len, len) <= k * 2);
}
function reverse( input) {
var temparray = input;
var left, right = 0;
right = temparray.length - 1;
for (left = 0; left < right; left++, right--)
{
var temp = temparray[left];
temparray[left] = temparray[right];
temparray[right] = temp;
}
return temparray;
}
var str = "acdcb" ;
var k = 2;
if (isKPal(str, k)) {
document.write( "Yes" );
} else {
document.write( "No" );
}
</script>
|
Time complexity: O(2n), It is exponential. In the worst case, we may end up doing O(2n) operations and the worst case happens string contains all distinct characters.
Auxiliary Space: O(1), since no extra space has been taken.
This problem has both properties (see this and this) of a dynamic programming problem. Like other typical Dynamic Programming(DP) problems, re-computations of the same subproblems can be avoided by constructing a temporary array that stores the results of subproblems .
Below is a Bottom-up implementation of the above recursive approach :
C++
#include <bits/stdc++.h>
using namespace std;
int isKPalDP(string str1, string str2, int m, int n)
{
int dp[m + 1][n + 1];
for ( int i = 0; i <= m; i++)
{
for ( int j = 0; j <= n; j++)
{
if (i == 0)
dp[i][j] = j;
else if (j == 0)
dp[i][j] = i;
else if (str1[i - 1] == str2[j - 1])
dp[i][j] = dp[i - 1][j - 1];
else
dp[i][j] = 1 + min(dp[i - 1][j],
dp[i][j - 1]);
}
}
return dp[m][n];
}
bool isKPal(string str, int k)
{
string revStr = str;
reverse(revStr.begin(), revStr.end());
int len = str.length();
return (isKPalDP(str, revStr, len, len) <= k*2);
}
int main()
{
string str = "acdcb" ;
int k = 2;
isKPal(str, k)? cout << "Yes" : cout << "No" ;
return 0;
}
|
Java
import java.util.*;
import java.io.*;
class GFG
{
static int isKPalDP(String str1,
String str2, int m, int n)
{
int dp[][] = new int [m + 1 ][n + 1 ];
for ( int i = 0 ; i <= m; i++)
{
for ( int j = 0 ; j <= n; j++)
{
if (i == 0 )
{
dp[i][j] = j;
}
else if (j == 0 )
{
dp[i][j] = i;
}
else if (str1.charAt(i - 1 ) ==
str2.charAt(j - 1 ))
{
dp[i][j] = dp[i - 1 ][j - 1 ];
}
else
{
dp[i][j] = 1 + Math.min(dp[i - 1 ][j],
dp[i][j - 1 ]);
}
}
}
return dp[m][n];
}
static boolean isKPal(String str, int k)
{
String revStr = str;
revStr = reverse(revStr);
int len = str.length();
return (isKPalDP(str, revStr,
len, len) <= k * 2 );
}
static String reverse(String str)
{
StringBuilder sb = new StringBuilder(str);
sb.reverse();
return sb.toString();
}
public static void main(String[] args)
{
String str = "acdcb" ;
int k = 2 ;
if (isKPal(str, k))
{
System.out.println( "Yes" );
}
else
{
System.out.println( "No" );
}
}
}
|
Python3
def isKPalDP(str1, str2, m, n):
dp = [[ 0 ] * (n + 1 ) for _ in range (m + 1 )]
for i in range (m + 1 ):
for j in range (n + 1 ):
if not i :
dp[i][j] = j
elif not j :
dp[i][j] = i
elif (str1[i - 1 ] = = str2[j - 1 ]):
dp[i][j] = dp[i - 1 ][j - 1 ]
else :
dp[i][j] = 1 + min (dp[i - 1 ][j],
(dp[i][j - 1 ]))
return dp[m][n]
def isKPal(string, k):
revStr = string[:: - 1 ]
l = len (string)
return (isKPalDP(string, revStr, l, l) < = k * 2 )
string = "acdcb"
k = 2
print ( "Yes" if isKPal(string, k) else "No" )
|
C#
using System;
class GFG {
static int isKPalDP( string str1,
string str2, int m, int n)
{
int [,] dp = new int [m + 1, n + 1];
for ( int i = 0; i <= m; i++)
{
for ( int j = 0; j <= n; j++)
{
if (i == 0)
{
dp[i, j] = j;
}
else if (j == 0)
{
dp[i, j] = i;
}
else if (str1[i - 1] == str2[j - 1])
{
dp[i, j] = dp[i - 1, j - 1];
}
else
{
dp[i, j] = 1 + Math.Min(dp[i - 1, j], dp[i, j - 1]);
}
}
}
return dp[m, n];
}
static bool isKPal( string str, int k)
{
string revStr = str;
revStr = reverse(revStr);
int len = str.Length;
return (isKPalDP(str, revStr, len, len) <= k * 2);
}
static string reverse( string str)
{
char [] sb = str.ToCharArray();
Array.Reverse(sb);
return new string (sb);
}
static void Main() {
string str = "acdcb" ;
int k = 2;
if (isKPal(str, k))
{
Console.WriteLine( "Yes" );
}
else
{
Console.WriteLine( "No" );
}
}
}
|
Javascript
<script>
function isKPalDP( str1, str2 , m , n) {
var dp = Array(m + 1).fill().map(()=>Array(n + 1).fill(0));
for (i = 0; i <= m; i++) {
for (j = 0; j <= n; j++) {
if (i == 0) {
dp[i][j] = j;
}
else if (j == 0) {
dp[i][j] = i;
}
else if (str1.charAt(i - 1) == str2.charAt(j - 1)) {
dp[i][j] = dp[i - 1][j - 1];
}
else {
dp[i][j] = 1 + Math.min(dp[i - 1][j], dp[i][j - 1]);
}
}
}
return dp[m][n];
}
function isKPal( str , k) {
var revStr = str;
revStr = reverse(revStr);
var len = str.length;
return (isKPalDP(str, revStr, len, len) <= k * 2);
}
function reverse( str) {
return str.split( '' ).reverse().join( '' );
}
var str = "acdcb" ;
var k = 2;
if (isKPal(str, k)) {
document.write( "Yes" );
} else {
document.write( "No" );
}
</script>
|
Time complexity: O(n2), Where n is the length of the given string
Auxiliary Space: O(n2), For creating 2D dp array
Alternate Approach :
1) Find Length of the Longest Palindromic Subsequence
2) If the difference between lengths of the original string and the longest palindromic subsequence is less than or equal k, return true. Else return false.
Find if string is K-Palindrome or not | Set 2 (Using LCS)
This article is contributed by Aditya Goel. If you like GeeksforGeeks and would like to contribute, you can also write an article and mail your article to review-team@geeksforgeeks.org. See your article appearing on the GeeksforGeeks main page and help other Geeks.
Please write comments if you find anything incorrect, or you want to share more information about the topic discussed above