Open In App

Longest Substring that can be made a palindrome by swapping of characters

Improve
Improve
Like Article
Like
Save
Share
Report

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++




// C++ program for the above approach
#include <bits/stdc++.h>
using namespace std;
 
// Function to find the Longest
// substring that can be made a
// palindrome by swapping of characters
int longestSubstring(string s)
{
   
    // Initialize dp array of size 1024
    int dp[1024];
 
    // Initializeing dp array with length of s
    fill(dp, dp + 1024, s.size());
 
    // Initializing mask and res
    int res = 0, mask = 0;
    dp[0] = -1;
 
    // Traverse the string
    for (int i = 0; i < s.size(); ++i)
    {
 
        // Find the mask of the current character
        mask ^= 1 << (s[i] - 48);
 
        // Finding the length of the longest
        // substring in s which is a
        // palindrome for even count
        res = max(res, i - dp[mask]);
 
        // Finding the length of the longest
        // substring in s which is a
        // palindrome for one odd count
        for (int j = 0; j <= 9; ++j)
 
            // Finding maximum length of
            // substring having one odd count
            res = max(res, i - dp[mask ^ (1 << j)]);
 
        // dp[mask] is minimum of
        // current i and dp[mask]
        dp[mask] = min(dp[mask], i);
    }
 
    // Return longest length of the substring
    // which forms a palindrome with swaps
    return res;
}
 
// Driver Code
int main()
{
   
    // Input String
    string s = "3242415";
 
    // Function Call
    cout << longestSubstring(s);
    return 0;
}
 
// This code is contributed by subhammahato348.


Java




// Java program for the above approach
 
import java.io.*;
import java.util.*;
 
class GFG {
 
    // Function to find the Longest
    // substring that can be made a
    // palindrome by swapping of characters
    public static int longestSubstring(String s)
    {
        // Initialize dp array of size 1024
        int dp[] = new int[1024];
 
        // Initializeing dp array with length of s
        Arrays.fill(dp, s.length());
 
        // Initializing mask and res
        int res = 0, mask = 0;
        dp[0] = -1;
 
        // Traverse the string
        for (int i = 0; i < s.length(); ++i) {
 
            // Find the mask of the current character
            mask ^= 1 << (s.charAt(i) - '0');
 
            // Finding the length of the longest
            // substring in s which is a
            // palindrome for even count
            res = Math.max(res, i - dp[mask]);
 
            // Finding the length of the longest
            // substring in s which is a
            // palindrome for one odd count
            for (int j = 0; j <= 9; ++j)
 
                // Finding maximum length of
                // substring having one odd count
                res = Math.max(res,
                               i - dp[mask ^ (1 << j)]);
 
            // dp[mask] is minimum of
            // current i and dp[mask]
            dp[mask] = Math.min(dp[mask], i);
        }
 
        // Return longest length of the substring
        // which forms a palindrome with swaps
        return res;
    }
 
    // Driver Code
    public static void main(String[] args)
    {
        // Input String
        String s = "3242415";
 
        // Function Call
        System.out.println(longestSubstring(s));
    }
}


Python3




# Python3 program for the above approach
 
# Function to find the Longest
# substring that can be made a
# palindrome by swapping of characters
def longestSubstring(s):
     
    # Initialize dp array of size 1024
    dp = [1024 for i in range(1024)]
 
    # Initializeing dp array with length of s
    # Arrays.fill(dp, s.length());
 
    # Initializing mask and res
    res, mask = 0, 0
    dp[0] = -1
 
    # Traverse the string
    for i in range(len(s)):
         
        # Find the mask of the current character
        mask ^= 1 << (ord(s[i]) - ord('0'))
 
        # Finding the length of the longest
        # substring in s which is a
        # palindrome for even count
        res = max(res, i - dp[mask])
 
        # Finding the length of the longest
        # substring in s which is a
        # palindrome for one odd count
        for j in range(10):
             
            # Finding maximum length of
            # substring having one odd count
            res = max(res, i - dp[mask ^ (1 << j)])
 
        # dp[mask] is minimum of
        # current i and dp[mask]
        dp[mask] = min(dp[mask], i)
 
    # Return longest length of the substring
    # which forms a palindrome with swaps
    return res
 
# Driver Code
if __name__ == '__main__':
     
    # Input String
    s = "3242415"
 
    # Function Call
    print(longestSubstring(s))
 
# This code is contributed by mohit kumar 29


C#




// C# program for the above approach
using System;
class GFG
{
 
  // Function to find the Longest
  // substring that can be made a
  // palindrome by swapping of characters
  public static int longestSubstring(string s)
  {
    // Initialize dp array of size 1024
    int []dp = new int[1024];
 
    // Initializeing dp array with length of s
    for (int i = 0; i < 1024; ++i)
    {
      dp[i] = s.Length;
    }
 
    // Initializing mask and res
    int res = 0, mask = 0;
    dp[0] = -1;
 
    // Traverse the string
    for (int i = 0; i < s.Length; i++)
    {
 
      // Find the mask of the current character
      mask = mask ^ (1 << (s[i] - '0'));
 
      // Finding the length of the longest
      // substring in s which is a
      // palindrome for even count
      res = Math.Max(res, i - dp[mask]);
 
      // Finding the length of the longest
      // substring in s which is a
      // palindrome for one odd count
      for (int j = 0; j < 10; j++)
      {
 
        // Finding maximum length of
        // substring having one odd count
        res = Math.Max(res,i - dp[mask ^ (1 << j)]);
      }
 
      // dp[mask] is minimum of
      // current i and dp[mask]
      dp[mask] = Math.Min(dp[mask], i);
    }
 
    // Return longest length of the substring
    // which forms a palindrome with swaps
    return res;
  }
 
  // Driver Code
  public static void Main(string[] args)
  {
 
    // Input String
    string s = "3242415";
 
    // Function Call
    Console.WriteLine(longestSubstring(s));
  }
}
 
// This code is contributed by AnkThon


Javascript




<script>
 
// Javascript program for the above approach
 
// Function to find the Longest
// substring that can be made a
// palindrome by swapping of characters
function longestSubstring(s)
{
     
    // Initialize dp array of size 1024
    let dp = new Array(1024).fill(1);
 
    // Initializing mask and res
    let res = 0, mask = 0;
    dp[0] = -1;
 
    // Traverse the string
    for(let i = 0; i < s.length; ++i)
    {
         
        // Find the mask of the current character
        mask ^= 1 << (s[i] - '0');
 
        // Finding the length of the longest
        // substring in s which is a
        // palindrome for even count
        res = Math.max(res, i - dp[mask]);
 
        // Finding the length of the longest
        // substring in s which is a
        // palindrome for one odd count
        for(let j = 0; j <= 9; ++j)
         
            // Finding maximum length of
            // substring having one odd count
            res = Math.max(res,
                           i - dp[mask ^ (1 << j)]);
 
        // dp[mask] is minimum of
        // current i and dp[mask]
        dp[mask] = Math.min(dp[mask], i);
    }
 
    // Return longest length of the substring
    // which forms a palindrome with swaps
    return res;
}
 
// Driver Code
 
// Input String
let s = "3242415";
 
// Function Call
document.write(longestSubstring(s));
 
// This code is contributed by splevel62
   
</script>


Output

5





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++




// C++ program for above approach
#include <iostream>
#include <vector>
using namespace std;
 
int longestSubstring(string s) {
    vector<int> counts(10, 0); // Store the count of each digit
 
    // Count the frequency of each digit in the string
    for (char c : s) {
        int digit = c - '0';
        counts[digit] += 1;
    }
 
    // Check for the longest palindrome length
    int maxPalindromeLength = 0;
    bool oddCount = false; // Flag to track if odd count digit is encountered
 
    for (int count : counts) {
        if (count % 2 == 0) {
            maxPalindromeLength += count;
        } else {
            maxPalindromeLength += count - 1;
            oddCount = true;
        }
    }
 
    if (oddCount) {
        maxPalindromeLength += 1;
    }
 
    return maxPalindromeLength;
}
//Driver code
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]; // Store the count of each digit
 
        // Count the frequency of each digit in the string
        for (char c : s.toCharArray()) {
            int digit = Character.getNumericValue(c);
            counts[digit] += 1;
        }
 
        // Check for the longest palindrome length
        int maxPalindromeLength = 0;
        boolean oddCount = false; // Flag to track if odd count digit is encountered
 
        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  # Store the count of each digit
 
    # Count the frequency of each digit in the string
    for char in s:
        digit = int(char)
        counts[digit] += 1
 
    # Check for the longest palindrome length
    maxPalindromeLength = 0
    oddCount = False  # Flag to track if odd count digit is encountered
 
    for count in counts:
        if count % 2 == 0:
            maxPalindromeLength += count
        else:
            maxPalindromeLength += count - 1
            oddCount = True
 
    if oddCount:
        maxPalindromeLength += 1
 
    return maxPalindromeLength
 
 
# Driver code
s = "3242415"
print(longestSubstring(s))


C#




// C# program for above approach
using System;
using System.Collections.Generic;
 
class GFG
{
    static int LongestSubstring(string s)
    {
        // Create a dictionary to store the count of each digit
        Dictionary<int, int> counts = new Dictionary<int, int>();
 
        // Count the frequency of each digit in the string
        foreach (char c in s)
        {
            int digit = c - '0';
            if (counts.ContainsKey(digit))
                counts[digit]++;
            else
                counts[digit] = 1;
        }
 
        // Check for the longest palindrome length
        int maxPalindromeLength = 0;
        bool oddCount = false; // Flag to track if odd count digit is encountered
 
        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); // Store the count of each digit
 
    // Count the frequency of each digit in the string
    for (let i = 0; i < s.length; i++) {
        const digit = parseInt(s[i]);
        counts[digit] += 1;
    }
 
    // Check for the longest palindrome length
    let maxPalindromeLength = 0;
    let oddCount = false; // Flag to track if odd count digit is encountered
 
    for (const count of counts) {
        if (count % 2 === 0) {
            maxPalindromeLength += count;
        } else {
            maxPalindromeLength += count - 1;
            oddCount = true;
        }
    }
 
    if (oddCount) {
        maxPalindromeLength += 1;
    }
 
    return maxPalindromeLength;
}
 
// Driver code
const s = "3242415";
console.log(longestSubstring(s));


Output

5






Time complexity: O(n)
Auxiliary Space :  O(1) 



Last Updated : 25 Sep, 2023
Like Article
Save Article
Previous
Next
Share your thoughts in the comments
Similar Reads