Longest Substring that can be made a palindrome by swapping of characters
Last Updated :
25 Sep, 2023
Given a numeric string S, the task is to find the longest non-empty substring that can be made palindrome.
Examples:
Input: S = “3242415”
Output: 5
Explanation: “24241” is the longest such substring which can be converted to the palindromic string “24142”.
Input: S = “213123”
Output: 6
Explanation: “213123” such substring which can be converted to the palindromic string “231132”.
Naive Approach: The simplest approach to solve this problem is to generate all possible substrings and for each substring check if it can be made a palindrome or not by counting the characters in each substring and check if only one or no odd frequent character is present or not.
Time Complexity: O(N3)
Auxiliary Space: O(1)
Efficient Approach: To optimize the above approach, the idea to solve this problem is to use Bitmasking and Dynamic Programming. A palindrome can be formed if the count of each included number (except maybe one) is even. Follow the steps below to solve the problem:
- Initialize an integer variable, say mask. A bit in our mask is 0 if the count for the corresponding number is even, and 1 if it’s odd.
- Traverse through the string and while traversing the string, track odd/even counts in the variable mask.
- If the same mask is encountered again, the subarray between the first position (exclusive) and the current position (inclusive) with the same mask has all numbers with the even count.
- Let the size of the substring be stored in a variable, say res.
- Initialize an array, say dp[], to track the smallest (first) position of each mask of size 1024, since the input only contains 10 digits (“0123456789”), and there can be only 2^10 or 1024 variations of bit masks.
- The size of the substring can be calculated by subtracting it from the current position. Note that the position for zero mask is -1, as the first character is to be included.
- Also, check all masks that are different from the current one by one bit. In other words, if two masks are different by one bit, that means that there is one odd count in the substring.
- Print res as the length of longest such substring.
Below is the implementation of the above approach:
C++
#include <bits/stdc++.h>
using namespace std;
int longestSubstring(string s)
{
int dp[1024];
fill(dp, dp + 1024, s.size());
int res = 0, mask = 0;
dp[0] = -1;
for ( int i = 0; i < s.size(); ++i)
{
mask ^= 1 << (s[i] - 48);
res = max(res, i - dp[mask]);
for ( int j = 0; j <= 9; ++j)
res = max(res, i - dp[mask ^ (1 << j)]);
dp[mask] = min(dp[mask], i);
}
return res;
}
int main()
{
string s = "3242415" ;
cout << longestSubstring(s);
return 0;
}
|
Java
import java.io.*;
import java.util.*;
class GFG {
public static int longestSubstring(String s)
{
int dp[] = new int [ 1024 ];
Arrays.fill(dp, s.length());
int res = 0 , mask = 0 ;
dp[ 0 ] = - 1 ;
for ( int i = 0 ; i < s.length(); ++i) {
mask ^= 1 << (s.charAt(i) - '0' );
res = Math.max(res, i - dp[mask]);
for ( int j = 0 ; j <= 9 ; ++j)
res = Math.max(res,
i - dp[mask ^ ( 1 << j)]);
dp[mask] = Math.min(dp[mask], i);
}
return res;
}
public static void main(String[] args)
{
String s = "3242415" ;
System.out.println(longestSubstring(s));
}
}
|
Python3
def longestSubstring(s):
dp = [ 1024 for i in range ( 1024 )]
res, mask = 0 , 0
dp[ 0 ] = - 1
for i in range ( len (s)):
mask ^ = 1 << ( ord (s[i]) - ord ( '0' ))
res = max (res, i - dp[mask])
for j in range ( 10 ):
res = max (res, i - dp[mask ^ ( 1 << j)])
dp[mask] = min (dp[mask], i)
return res
if __name__ = = '__main__' :
s = "3242415"
print (longestSubstring(s))
|
C#
using System;
class GFG
{
public static int longestSubstring( string s)
{
int []dp = new int [1024];
for ( int i = 0; i < 1024; ++i)
{
dp[i] = s.Length;
}
int res = 0, mask = 0;
dp[0] = -1;
for ( int i = 0; i < s.Length; i++)
{
mask = mask ^ (1 << (s[i] - '0' ));
res = Math.Max(res, i - dp[mask]);
for ( int j = 0; j < 10; j++)
{
res = Math.Max(res,i - dp[mask ^ (1 << j)]);
}
dp[mask] = Math.Min(dp[mask], i);
}
return res;
}
public static void Main( string [] args)
{
string s = "3242415" ;
Console.WriteLine(longestSubstring(s));
}
}
|
Javascript
<script>
function longestSubstring(s)
{
let dp = new Array(1024).fill(1);
let res = 0, mask = 0;
dp[0] = -1;
for (let i = 0; i < s.length; ++i)
{
mask ^= 1 << (s[i] - '0' );
res = Math.max(res, i - dp[mask]);
for (let j = 0; j <= 9; ++j)
res = Math.max(res,
i - dp[mask ^ (1 << j)]);
dp[mask] = Math.min(dp[mask], i);
}
return res;
}
let s = "3242415" ;
document.write(longestSubstring(s));
</script>
|
Time Complexity: O(10*N)
Auxiliary Space: O(1024)
New Approach:- Here is another approach to solve this problem
The approach counts the frequency of each digit in the string, adds the counts of even digits to the `maxPalindromeLength`, and considers the counts of odd digits. If there is at least one odd count digit, it subtracts 1 from the count and adds it to `maxPalindromeLength`, considering that one odd digit can be placed at the center of the palindrome. The result is the length of the longest substring that can be made a palindrome by swapping characters in the given string.
Below is the implementation of the above approach:
C++
#include <iostream>
#include <vector>
using namespace std;
int longestSubstring(string s) {
vector< int > counts(10, 0);
for ( char c : s) {
int digit = c - '0' ;
counts[digit] += 1;
}
int maxPalindromeLength = 0;
bool oddCount = false ;
for ( int count : counts) {
if (count % 2 == 0) {
maxPalindromeLength += count;
} else {
maxPalindromeLength += count - 1;
oddCount = true ;
}
}
if (oddCount) {
maxPalindromeLength += 1;
}
return maxPalindromeLength;
}
int main() {
string s = "3242415" ;
cout << longestSubstring(s) << endl;
return 0;
}
|
Java
public class Main {
public static int longestSubstring(String s) {
int [] counts = new int [ 10 ];
for ( char c : s.toCharArray()) {
int digit = Character.getNumericValue(c);
counts[digit] += 1 ;
}
int maxPalindromeLength = 0 ;
boolean oddCount = false ;
for ( int count : counts) {
if (count % 2 == 0 ) {
maxPalindromeLength += count;
} else {
maxPalindromeLength += count - 1 ;
oddCount = true ;
}
}
if (oddCount) {
maxPalindromeLength += 1 ;
}
return maxPalindromeLength;
}
public static void main(String[] args) {
String s = "3242415" ;
System.out.println(longestSubstring(s));
}
}
|
Python
def longestSubstring(s):
counts = [ 0 ] * 10
for char in s:
digit = int (char)
counts[digit] + = 1
maxPalindromeLength = 0
oddCount = False
for count in counts:
if count % 2 = = 0 :
maxPalindromeLength + = count
else :
maxPalindromeLength + = count - 1
oddCount = True
if oddCount:
maxPalindromeLength + = 1
return maxPalindromeLength
s = "3242415"
print (longestSubstring(s))
|
C#
using System;
using System.Collections.Generic;
class GFG
{
static int LongestSubstring( string s)
{
Dictionary< int , int > counts = new Dictionary< int , int >();
foreach ( char c in s)
{
int digit = c - '0' ;
if (counts.ContainsKey(digit))
counts[digit]++;
else
counts[digit] = 1;
}
int maxPalindromeLength = 0;
bool oddCount = false ;
foreach ( int count in counts.Values)
{
if (count % 2 == 0)
{
maxPalindromeLength += count;
}
else
{
maxPalindromeLength += count - 1;
oddCount = true ;
}
}
if (oddCount)
{
maxPalindromeLength += 1;
}
return maxPalindromeLength;
}
static void Main()
{
string s = "3242415" ;
Console.WriteLine(LongestSubstring(s));
}
}
|
Javascript
function longestSubstring(s) {
const counts = new Array(10).fill(0);
for (let i = 0; i < s.length; i++) {
const digit = parseInt(s[i]);
counts[digit] += 1;
}
let maxPalindromeLength = 0;
let oddCount = false ;
for (const count of counts) {
if (count % 2 === 0) {
maxPalindromeLength += count;
} else {
maxPalindromeLength += count - 1;
oddCount = true ;
}
}
if (oddCount) {
maxPalindromeLength += 1;
}
return maxPalindromeLength;
}
const s = "3242415" ;
console.log(longestSubstring(s));
|
Time complexity: O(n)
Auxiliary Space : O(1)
Share your thoughts in the comments
Please Login to comment...