Given a string s consisting of digits (0-9) and an integer k. Convert the string into a palindrome by changing at most k digits. If multiple palindromes are possible, return the lexicographically largest one. If it's impossible to form a palindrome with k changes, return "-1".
Examples:
Input: s = "19495", k = 3
Output: "99999"
Explanation: Change 1 and 5 to 9, and then change the middle digit 4 to 9, using exactly 3 changes to form the lexicographically largest palindrome "99999".Input: s = "11345", k = 1
Output: "-1"
Explanation: It is not possible to make s palindrome after 1 changes.
Table of Content
[Naive Approach] Recursion - O(10 ^ n * n) Time and O(n) Space
The idea is to try all possible digits at each position and generate every string that can be formed using at most k changes. Among the generated strings, keep the lexicographically largest palindrome.
Working of Approach:
- Recursively keep the current digit or change it to another digit.
- For every generated string, check if it is a palindrome.
- Update the answer whenever a larger palindrome is found.
#include <iostream>
#include <string>
using namespace std;
string res;
bool isPalindrome(string &s)
{
int i = 0, j = s.length() - 1;
while (i < j)
{
if (s[i] != s[j])
return false;
i++;
j--;
}
return true;
}
void generate(string &s, int pos, int k)
{
int n = s.length();
// Check the generated string.
if (pos == n)
{
if (isPalindrome(s) && s > res)
res = s;
return;
}
// Keep the current digit.
generate(s, pos + 1, k);
char original = s[pos];
// Try changing the digit.
for (char digit = '0'; digit <= '9'; digit++)
{
if (digit == original || k == 0)
continue;
s[pos] = digit;
generate(s, pos + 1, k - 1);
}
s[pos] = original;
}
string maxPalindrome(string &s, int k)
{
res = "";
generate(s, 0, k);
if (res == "")
return "-1";
return res;
}
int main()
{
string s = "19495";
int k = 3;
cout << "\"" << maxPalindrome(s, k) << "\"" << endl;
return 0;
}
import java.util.*;
public class GFG {
static String res;
static boolean isPalindrome(String s)
{
int i = 0, j = s.length() - 1;
while (i < j) {
if (s.charAt(i) != s.charAt(j))
return false;
i++;
j--;
}
return true;
}
static void generate(char[] s, int pos, int k)
{
int n = s.length;
// Check the generated string.
if (pos == n) {
if (isPalindrome(new String(s))
&& new String(s).compareTo(res) > 0)
res = new String(s);
return;
}
// Keep the current digit.
generate(s, pos + 1, k);
char original = s[pos];
// Try changing the digit.
for (char digit = '0'; digit <= '9'; digit++) {
if (digit == original || k == 0)
continue;
s[pos] = digit;
generate(s, pos + 1, k - 1);
}
s[pos] = original;
}
static String maxPalindrome(String s, int k)
{
res = "";
generate(s.toCharArray(), 0, k);
if (res.equals(""))
return "-1";
return res;
}
public static void main(String[] args)
{
String s = "19495";
int k = 3;
System.out.println("\"" + maxPalindrome(s, k)
+ "\"");
}
}
res = ""
def isPalindrome(s):
i = 0
j = len(s) - 1
while i < j:
if s[i] != s[j]:
return False
i += 1
j -= 1
return True
def generate(s, pos, k):
global res
n = len(s)
# Check the generated string.
if pos == n:
if isPalindrome(s) and s > res:
res = s
return
# Keep the current digit.
generate(s, pos + 1, k)
original = s[pos]
# Try changing the digit.
for digit in range(48, 58):
# Skip the original digit or if no changes are left.
if chr(digit) == original or k == 0:
continue
s = s[:pos] + chr(digit) + s[pos + 1:]
# Generate using one change.
generate(s, pos + 1, k - 1)
# Restore the original digit.
s = s[:pos] + original + s[pos + 1:]
def maxPalindrome(s, k):
global res
res = ""
generate(s, 0, k)
if res == "":
return "-1"
return res
if __name__ == '__main__':
s = "19495"
k = 3
print(maxPalindrome(s, k))
using System;
public class GFG {
static string res;
static bool IsPalindrome(string s)
{
int i = 0, j = s.Length - 1;
while (i < j) {
if (s[i] != s[j])
return false;
i++;
j--;
}
return true;
}
static void Generate(char[] s, int pos, int k)
{
int n = s.Length;
// Check the generated string.
if (pos == n) {
if (IsPalindrome(new string(s))
&& string.Compare(new string(s), res) > 0)
res = new string(s);
return;
}
// Keep the current digit.
Generate(s, pos + 1, k);
char original = s[pos];
// Try changing the digit.
for (char digit = '0'; digit <= '9'; digit++) {
if (digit == original || k == 0)
continue;
s[pos] = digit;
Generate(s, pos + 1, k - 1);
}
s[pos] = original;
}
static string maxPalindrome(string s, int k)
{
res = "";
Generate(s.ToCharArray(), 0, k);
if (res == "")
return "-1";
return res;
}
public static void Main()
{
string s = "19495";
int k = 3;
Console.WriteLine("\"" + maxPalindrome(s, k)
+ "\"");
}
}
function isPalindrome(s) {
let i = 0, j = s.length - 1;
while (i < j) {
if (s[i] !== s[j])
return false;
i++;
j--;
}
return true;
}
function generate(s, pos, k, resObj) {
let n = s.length;
// Check the generated string.
if (pos === n) {
let currentStr = s.join('');
if (isPalindrome(s) && currentStr > resObj.val)
resObj.val = currentStr;
return;
}
// Keep the current digit.
generate(s, pos + 1, k, resObj);
let original = s[pos];
// Try changing the digit.
for (let d = 0; d <= 9; d++) {
let digit = String(d);
if (digit === original || k === 0)
continue;
s[pos] = digit;
generate(s, pos + 1, k - 1, resObj);
}
s[pos] = original;
}
function maxPalindrome(sStr, k) {
let resObj = { val: "" };
let s = sStr.split('');
generate(s, 0, k, resObj);
if (resObj.val === "")
return "-1";
return resObj.val;
}
// Driver code
let s = "19495";
let k = 3;
console.log("\"" + maxPalindrome(s, k) + "\"");
Output
"99999"
[Better Approach] Two Pointers - O(n) time and O(n) space
The idea is to use two pointers from both ends to first make the string a palindrome. We store which pairs were changed, then use the remaining changes to make the palindrome lexicographically largest.
- Replace the smaller digit with the larger one and mark the pair as changed.
- Traverse again and change pairs to '9' using the remaining changes.
- If one change remains for an odd-length string, make the middle digit '9'.
Let us understand with an example:
Input: s = "19495", k = 3
- Compare 1 and 5 -> different, change 1 to 5, mark the pair, k = 2 -> "59495".
- Compare 9 and 9 -> same, no change -> "59495".
- Compare 4 with itself -> no change needed.
- Traverse again: change the marked pair 5 and 5 to 9, k = 1 -> "99499".
- Change the middle 4 to 9 -> "99999".
#include <algorithm>
#include <iostream>
#include <string>
#include <vector>
using namespace std;
string maxPalindrome(string &s, int k)
{
int n = s.length();
vector<bool> changed(n, false);
// Make the string a palindrome.
int i = 0, j = n - 1;
while (i < j)
{
if (s[i] != s[j])
{
// Replace the smaller digit with the larger digit.
if (s[i] < s[j])
s[i] = s[j];
else
s[j] = s[i];
// Mark this pair as changed.
changed[i] = changed[j] = true;
k--;
}
i++;
j--;
}
// Return -1 if it is not possible to make a palindrome.
if (k < 0)
return "-1";
// Maximize the palindrome using the remaining changes.
i = 0;
j = n - 1;
while (i < j)
{
if (s[i] != '9')
{
// One extra change is enough for an already changed pair.
if (changed[i] && k >= 1)
{
s[i] = s[j] = '9';
k--;
}
// Two changes are needed for an unchanged pair.
else if (!changed[i] && k >= 2)
{
s[i] = s[j] = '9';
k -= 2;
}
}
i++;
j--;
}
// Make the middle digit 9 if one change is available.
if (i == j && k > 0)
s[i] = '9';
// Return the largest possible palindrome.
return s;
}
int main()
{
string s = "19495";
int k = 3;
cout << "\"" << maxPalindrome(s, k) << "\"" << endl;
return 0;
}
import java.util.Arrays;
public class GFG {
public static String maxPalindrome(String s, int k)
{
int n = s.length();
boolean[] changed = new boolean[n];
Arrays.fill(changed, false);
// Make the string a palindrome.
int i = 0, j = n - 1;
while (i < j) {
if (s.charAt(i) != s.charAt(j)) {
// Replace the smaller digit with the larger
// digit.
if (s.charAt(i) < s.charAt(j))
s = s.substring(0, i) + s.charAt(j)
+ s.substring(i + 1);
else
s = s.substring(0, j) + s.charAt(i)
+ s.substring(j + 1);
// Mark this pair as changed.
changed[i] = changed[j] = true;
k--;
}
i++;
j--;
}
// Return -1 if it is not possible to make a
// palindrome.
if (k < 0)
return "-1";
// Maximize the palindrome using the remaining
// changes.
i = 0;
j = n - 1;
while (i < j) {
if (s.charAt(i) != '9') {
// One extra change is enough for an already
// changed pair.
if (changed[i] && k >= 1) {
s = s.substring(0, i) + '9'
+ s.substring(i + 1);
s = s.substring(0, j) + '9'
+ s.substring(j + 1);
k--;
}
// Two changes are needed for an unchanged
// pair.
else if (!changed[i] && k >= 2) {
s = s.substring(0, i) + '9'
+ s.substring(i + 1);
s = s.substring(0, j) + '9'
+ s.substring(j + 1);
k -= 2;
}
}
i++;
j--;
}
// Make the middle digit 9 if one change is
// available.
if (i == j && k > 0)
s = s.substring(0, i) + '9'
+ s.substring(i + 1);
// Return the largest possible palindrome.
return s;
}
public static void main(String[] args)
{
String s = "19495";
int k = 3;
System.out.println("\"" + maxPalindrome(s, k)
+ "\"");
}
}
def maxPalindrome(s, k):
n = len(s)
changed = [False] * n
# Make the string a palindrome.
i = 0
j = n - 1
while i < j:
if s[i]!= s[j]:
# Replace the smaller digit with the larger digit.
if s[i] < s[j]:
s = s[:i] + s[j] + s[i+1:]
else:
s = s[:j] + s[i] + s[j+1:]
# Mark this pair as changed.
changed[i] = changed[j] = True
k -= 1
i += 1
j -= 1
# Return -1 if it is not possible to make a palindrome.
if k < 0:
return "-1"
# Maximize the palindrome using the remaining changes.
i = 0
j = n - 1
while i < j:
if s[i]!= '9':
# One extra change is enough for an already changed pair.
if changed[i] and k >= 1:
s = s[:i] + '9' + s[i+1:]
s = s[:j] + '9' + s[j+1:]
k -= 1
# Two changes are needed for an unchanged pair.
elif not changed[i] and k >= 2:
s = s[:i] + '9' + s[i+1:]
s = s[:j] + '9' + s[j+1:]
k -= 2
i += 1
j -= 1
# Make the middle digit 9 if one change is available.
if i == j and k > 0:
s = s[:i] + '9' + s[i+1:]
# Return the largest possible palindrome.
return s
if __name__ == '__main__':
s = "19495"
k = 3
print(f'"{maxPalindrome(s, k)}"')
using System;
using System.Collections.Generic;
class GFG {
static string maxPalindrome(string s, int k)
{
int n = s.Length;
List<bool> changed = new List<bool>(new bool[n]);
// Make the string a palindrome.
int i = 0, j = n - 1;
while (i < j) {
if (s[i] != s[j]) {
// Replace the smaller digit with the larger
// digit.
if (s[i] < s[j])
s = s.Substring(0, i) + s[j]
+ s.Substring(i + 1);
else
s = s.Substring(0, j) + s[i]
+ s.Substring(j + 1);
// Mark this pair as changed.
changed[i] = changed[j] = true;
k--;
}
i++;
j--;
}
// Return -1 if it is not possible to make a
// palindrome.
if (k < 0)
return "-1";
// Maximize the palindrome using the remaining
// changes.
i = 0;
j = n - 1;
while (i < j) {
if (s[i] != '9') {
// One extra change is enough for an already
// changed pair.
if (changed[i] && k >= 1) {
char[] charArray = s.ToCharArray();
charArray[i] = charArray[j] = '9';
s = new string(charArray);
k--;
}
// Two changes are needed for an unchanged
// pair.
else if (!changed[i] && k >= 2) {
char[] charArray = s.ToCharArray();
charArray[i] = charArray[j] = '9';
s = new string(charArray);
k -= 2;
}
}
i++;
j--;
}
// Make the middle digit 9 if one change is
// available.
if (i == j && k > 0)
s = s.Substring(0, i) + '9'
+ s.Substring(i + 1);
// Return the largest possible palindrome.
return s;
}
static void Main(string[] args)
{
string s = "19495";
int k = 3;
Console.WriteLine("\"" + maxPalindrome(s, k)
+ "\"");
}
}
function maxPalindrome(s, k)
{
let n = s.length;
let changed = new Array(n).fill(false);
// Make the string a palindrome.
let i = 0, j = n - 1;
while (i < j) {
if (s[i] !== s[j]) {
// Replace the smaller digit with the larger
// digit.
if (s[i] < s[j]) {
s = s.substring(0, i) + s[j]
+ s.substring(i + 1);
}
else {
s = s.substring(0, j) + s[i]
+ s.substring(j + 1);
}
// Mark this pair as changed.
changed[i] = changed[j] = true;
k--;
}
i++;
j--;
}
// Return -1 if it is not possible to make a palindrome.
if (k < 0) {
return "-1";
}
// Maximize the palindrome using the remaining changes.
i = 0;
j = n - 1;
while (i < j) {
if (s[i] !== "9") {
// One extra change is enough for an already
// changed pair.
if (changed[i] && k >= 1) {
s = s.substring(0, i) + "9"
+ s.substring(i + 1);
s = s.substring(0, j) + "9"
+ s.substring(j + 1);
k--;
}
// Two changes are needed for an unchanged pair.
else if (!changed[i] && k >= 2) {
s = s.substring(0, i) + "9"
+ s.substring(i + 1);
s = s.substring(0, j) + "9"
+ s.substring(j + 1);
k -= 2;
}
}
i++;
j--;
}
// Make the middle digit 9 if one change is available.
if (i === j && k > 0) {
s = s.substring(0, i) + "9" + s.substring(i + 1);
}
// Return the largest possible palindrome.
return s;
}
// Driver Code
let s = "19495";
let k = 3;
console.log(`'${maxPalindrome(s, k)}'`);
Output
"99999"
[Expected Approach] Greedy Algorithm - O(n) time and O(1) space
In this approach, we greedily count the changes needed to make the string a palindrome. Then, use the remaining changes to make the palindrome as large as possible.
- Compare characters from both ends and count required changes.
- Traverse again and change the largest possible digits to '9'.
- If the required changes exceed k, return "-1".
Let us understand with an example:
Input: s = "19495", k = 3
- Compare 1 and 5 -> different, so replacements = 1.
- Compare 9 and 9 -> same, no change needed.
- Change 1 and 5 to 9 using 2 changes -> s = "99499", k = 1.
- Change the middle digit 4 to 9 -> s = "99999".
Return "99999".
#include <algorithm>
#include <iostream>
#include <string>
using namespace std;
string maxPalindrome(string &s, int k)
{
int n = s.length();
int replacements = 0;
// Count changes needed to make the string a palindrome.
for (int i = 0, j = n - 1; i < j; i++, j--)
{
if (s[i] != s[j])
{
replacements++;
// -1 if required changes exceed k.
if (replacements > k)
return "-1";
}
}
// Maximize the palindrome using the remaining changes.
for (int i = 0, j = n - 1; i <= j && k > 0; i++, j--)
{
// Maximize the middle digit for odd length.
if (i == j)
{
s[i] = '9';
}
// Handle different mirror digits.
else if (s[i] != s[j])
{
// Use one extra change to make both digits 9.
if (k - replacements >= 1 && max(s[i], s[j]) != '9')
{
s[i] = s[j] = '9';
replacements--;
k -= 2;
}
// Otherwise, make both digits equal to the larger digit.
else
{
s[i] = s[j] = max(s[i], s[j]);
replacements--;
k--;
}
}
// Make an equal pair 9 if two extra changes are available.
else if (k - replacements >= 2 && s[i] != '9')
{
s[i] = s[j] = '9';
k -= 2;
}
}
// Return the largest possible palindrome.
return s;
}
int main()
{
string s = "19495";
int k = 3;
cout << "\"" << maxPalindrome(s, k) << "\"" << endl;
return 0;
}
import java.util.*;
public class GFG {
public static String maxPalindrome(String s, int k)
{
int n = s.length();
int replacements = 0;
// Count changes needed to make the string a
// palindrome.
for (int i = 0, j = n - 1; i < j; i++, j--) {
if (s.charAt(i) != s.charAt(j)) {
replacements++;
// -1 if required changes exceed k.
if (replacements > k)
return "-1";
}
}
// Maximize the palindrome using the remaining
// changes.
char[] charArray = s.toCharArray();
for (int i = 0, j = n - 1; i <= j && k > 0;
i++, j--) {
// Maximize the middle digit for odd length.
if (i == j) {
charArray[i] = '9';
}
// Handle different mirror digits.
else if (charArray[i] != charArray[j]) {
// Use one extra change to make both
// digits 9.
if (k - replacements >= 1
&& Math.max(charArray[i], charArray[j])
!= '9') {
charArray[i] = charArray[j] = '9';
replacements--;
k -= 2;
}
// Otherwise, make both digits equal to the
// larger digit.
else {
charArray[i] = charArray[j]
= (char)Math.max(charArray[i],
charArray[j]);
replacements--;
k--;
}
}
// Make an equal pair 9 if two extra changes are
// available.
else if (k - replacements >= 2
&& charArray[i] != '9') {
charArray[i] = charArray[j] = '9';
k -= 2;
}
}
return new String(charArray);
}
public static void main(String[] args)
{
String s = "19495";
int k = 3;
System.out.println("\"" + maxPalindrome(s, k)
+ "\"");
}
}
def maxPalindrome(s, k):
n = len(s)
replacements = 0
# Count changes needed to make the string a palindrome.
for i in range(n // 2):
if s[i] != s[n - 1 - i]:
replacements += 1
# -1 if required changes exceed k.
if replacements > k:
return "-1"
# Maximize the palindrome using the remaining changes.
s = list(s)
for i in range((n + 1) // 2):
j = n - 1 - i
if k <= 0:
break
# Maximize the middle digit for odd length.
if i == j:
s[i] = '9'
# Handle different mirror digits.
elif s[i] != s[j]:
# Use one extra change to make both digits 9.
if k - replacements >= 1 and max(s[i], s[j]) != '9':
s[i] = s[j] = '9'
replacements -= 1
k -= 2
# Otherwise, make both digits equal to the larger digit.
else:
s[i] = s[j] = max(s[i], s[j])
replacements -= 1
k -= 1
# Make an equal pair 9 if two extra changes are available.
elif k - replacements >= 2 and s[i] != '9':
s[i] = s[j] = '9'
k -= 2
return ''.join(s)
if __name__ == '__main__':
s = "19495"
k = 3
print(f'"{maxPalindrome(s, k)}"')
using System;
class GFG {
static string maxPalindrome(string s, int k)
{
int n = s.Length;
int replacements = 0;
// Count changes needed to make the string a
// palindrome.
for (int i = 0, j = n - 1; i < j; i++, j--) {
if (s[i] != s[j]) {
replacements++;
// -1 if required changes exceed k.
if (replacements > k)
return "-1";
}
}
// Maximize the palindrome using the remaining
// changes.
char[] charArray = s.ToCharArray();
for (int i = 0, j = n - 1; i <= j && k > 0;
i++, j--) {
// Maximize the middle digit for odd length.
if (i == j) {
charArray[i] = '9';
}
// Handle different mirror digits.
else if (charArray[i] != charArray[j]) {
// Use one extra change to make both
// digits 9.
if (k - replacements >= 1
&& Math.Max(charArray[i], charArray[j])
!= '9') {
charArray[i] = charArray[j] = '9';
replacements--;
k -= 2;
}
// Otherwise, make both digits equal to the
// larger digit.
else {
charArray[i] = charArray[j]
= (char)Math.Max(charArray[i],
charArray[j]);
replacements--;
k--;
}
}
// Make an equal pair 9 if two extra changes are
// available.
else if (k - replacements >= 2
&& charArray[i] != '9') {
charArray[i] = charArray[j] = '9';
k -= 2;
}
}
return new string(charArray);
}
static void Main()
{
string s = "19495";
int k = 3;
Console.WriteLine("\"" + maxPalindrome(s, k)
+ "\"");
}
}
function maxPalindrome(s, k)
{
let n = s.length;
let replacements = 0;
// Count changes needed to make the string a palindrome.
for (let i = 0, j = n - 1; i < j; i++, j--) {
if (s[i] !== s[j]) {
replacements++;
// -1 if required changes exceed k.
if (replacements > k)
return "-1";
}
}
// Maximize the palindrome using the remaining changes.
let sArray = s.split("");
for (let i = 0, j = n - 1; i <= j && k > 0; i++, j--) {
// Maximize the middle digit for odd length.
if (i === j) {
sArray[i] = "9";
}
// Handle different mirror digits.
else if (sArray[i] !== sArray[j]) {
// Use one extra change to make both digits 9.
if (k - replacements >= 1
&& Math.max(Number(sArray[i]),
Number(sArray[j]))
!== 9) {
sArray[i] = sArray[j] = "9";
replacements--;
k -= 2;
}
// Otherwise, make both digits equal to the
// larger digit.
else {
let larger = Math.max(Number(sArray[i]),
Number(sArray[j]));
sArray[i] = sArray[j] = String(larger);
replacements--;
k--;
}
}
// Make an equal pair 9 if two extra changes are
// available.
else if (k - replacements >= 2
&& sArray[i] !== "9") {
sArray[i] = sArray[j] = "9";
k -= 2;
}
}
return sArray.join("");
}
// Driver Code
let s = "19495";
let k = 3;
console.log(`"${maxPalindrome(s, k)}"`);
Output
"99999"