'Check if a permutation of a string can become a palindrome

Write a method to test if a string meets the preconditions to become a palindrome.

Eg:

Input    | Output
mmo      | True  
yakak    | True  
travel   | False

I'm thinking of this approach:

  1. Make a suffix tree for all permutation of T such that T$Reverse(T)#
  2. Check for all permutation for same node

Am I missing anything?



Solution 1:[1]

Really all you're looking for is if all (or all but one) of the letters are paired off. As long as they are, then they will be able to be turned into a palindrome.

So it would be something like...

bool canBeTurnedIntoAPalindrome(string drome)
{
  // If we've found a letter that has no match, the center letter.
  bool centerUsed = false;
  char center;

  char c;
  int count = 0;

  // TODO: Remove whitespace from the string.

  // Check each letter to see if there's an even number of it.
  for(int i = 0; i<drome.length(); i++)
  {
    c = drome[i];
    count = 0;

    for(int j = 0; j < drome.length(); j++)
      if (drome[j] == c)
         count++;

    // If there was an odd number of those entries
    // and the center is already used, then a palindrome
    // is impossible, so return false.
    if (count % 2 == 1)
    {
      if (centerUsed == true && center != c)
        return false;
      else
      {
        centerused = true;
        center = c;   // This is so when we encounter it again it
                      // doesn't count it as another separate center.
      }
    }
  }
  // If we made it all the way through that loop without returning false, then
  return true;
}

This isn't the most efficient (it's counting letters as many times as it comes across them, even if they've been counted already) but it does work.

Solution 2:[2]

All you need to do is check that there's at most one character with an odd number of occurrences. Here's a Java example:

private static boolean canMakePalindrom(String s) {
    Map<Character, Integer> countChars = new HashMap<>();

    // Count the occurrences of each character
    for (char c : s.toCharArray()) {
        Integer count = countChars.get(c);
        if (count == null) {
            count = Integer.valueOf(1);
        } else {
            count = count + 1;
        }
        countChars.put(c, count);
    }

    boolean hasOdd = false;
    for (int count : countChars.values()) {
        if (count % 2 == 1) {
            if (hasOdd) {
                // Found two chars with odd counts - return false;
                return false;
            } else {
                // Found the first char with odd count
                hasOdd = true;
            }
        }
     }

     // Haven't found more than one char with an odd count
     return true;
}

EDIT4 (yes - these are ordered to make sense, but numbered by chronological order):
The above implementation has a built in inefficiency. I don't think the first iteration over the string can be avoided, but there's no real reason to keep a count of all the occurrences - it's enough to just keep track of those with the an odd count. For this usecase, it's enough to keep track of each character we encounter (e.g., with a Set), and remove it when we encounter it again. In the worst case, where all the characters in the string are different, the performance is comparable, but in the common case, where there are several occurrences of each character, this implementation improves both time and memory complexity of the second loop (which is now reduced to a single condition) dramatically:

private static boolean canMakePalindrom(String s) {
    Set<Character> oddChars = new HashSet<>();

    // Go over the characters
    for (char c : s.toCharArray()) {
        // Record the encountered character:
        if (!oddChars.add(c)) {
            // If the char was already encountered, remove it - 
            // this is an even time we encounter it
            oddChars.remove(c);
        }
    }

    // Check the number of characters with odd counts:
    return oddChars.size() <= 1;
}

EDIT3 (yes - these are ordered to make sense, but numbered by chronological order):
Java 8 provides a fluent streaming API which could be used to create an implementation similar to the Python one-liners below:

private static boolean canMakePalindrom(String s) {
    return s.chars()
            .boxed()
            .collect(Collectors.groupingBy(Function.identity(),
                                           Collectors.counting()))
            .values()
            .stream()
            .filter(p -> p % 2 == 1)
            .count() <= 1;
}

EDIT:
Python built-in functions and comprehension capabilities make this too attractive not to publish this one liner solution. It's probably less efficient than the aforementioned Java one, but is quite elegant:

from collections import Counter

def canMakePalindrom(s):
    return len([v for v in Counter(s).values() if v % 2 == 1]) <= 1

EDIT2:
Or, an even cleaner approach as proposed by @DSM in the comments:

from collections import Counter

def canMakePalindrom(s):
    return sum(v % 2 == 1 for v in Counter(s).values()) <= 1

Solution 3:[3]

Instead of counting how many times each letter occurs, another approach keeps track of whether a letter has occurred an odd or even number of times. If a letter has occurred an even number of times, you don’t need to worry about it, and only need to keep track of the odd occurrences in a set. In Java:

public static boolean canMakePalindrome(String s) {
    Set<Character> oddLetters = new HashSet<>();
    for ( char c : s.toCharArray() ) {
        if ( ! oddLetters.remove(c) ) {
            oddLetters.add(c);
        }
    }
    return oddLetters.size() <= 1;
}

Solution 4:[4]

If I'm understanding your question correctly, this is how I understand it:

If the input string can be rearranged into a palindrome, output "True", otherwise output "False".

Then you can use these simple rules:

  1. If the length is even, every unique character in the input has to occur a multiple of 2 times.
  2. If the length is odd, every unique character except one has to occur a multiple of 2 times. Only 1 character is allowed to not occur a multiple of 2 times.

So for the 3 given examples:

"mmo", odd length, m occurs twice (multiple of 2), o occurs once (not a multiple of 2), so True.

"yakak", odd length, a occurs twice (multiple of 2), k occurs twice (multiple of 2), y occurs once (not a multiple of 2) , so True.

"travel", more than one character does not occur a multiple of 2, so False.

Additional examples:

"mmorpg", only m occurs a multiple of 2, the rest only once, so False.

"mmom", no characters occur a multiple of 2, more than one character occurs "not a multiple of 2 times", so False.

At this point you should realise that if only 1 character is allowed to occur a non-multiple-of-2 times, then you can disregard the length. A string with an even length will have either 2 or more characters occuring a non-multiple-of-2 times, or none at all.

So the final rule should be this:

If at most 1 unique character occurs a non-multiple-of-2 times in the input, the output is True otherwise the output is False.

Solution 5:[5]

def can_permutation_palindrome(s):
    counter = {}
    for c in s:
        counter[c] = counter.get(c, 0) + 1
    odd_count = 0
    for count in counter.values():
        odd_count += count % 2
    return odd_count in [0, 1]

Solution 6:[6]

I reached the solution below today (python). I think it's readable, and performance-wise it's really good.

sum(map(lambda x: word.count(x) % 2, set(word))) <= 1

We're basically counting the number of occurrences of each character in the string "word", getting the remainder of the division by 2, summing them all and checking if you have at most 1 of them.

The idea is that you need to have all characters paired, except potentially for one (the middle one).

Solution 7:[7]

def check(string):
    bv = 0
    for s in string:
        bv ^= 1 << ord(s)
    return bv == 0 or bv & (bv - 1) == 0

Solution 8:[8]

My idea is, if the number of letters with odd count is one and rest all have even count, a palindrome is possible..Here's my program in Python

string = raw_input()

found = False
char_set = set(string) # Lets find unique letters

d_dict = {}
for c in char_set:
    d_dict[c] = string.count(c) # Keep count of each letter

odd_l = [e for e in d_dict.values() if e%2 == 1] # Check how many has odd number of occurrence     
if len(odd_l) >1:
    pass
else:
    found = True



if not found:
    print("NO")
else:
    print("YES")

Solution 9:[9]

Any string can be palindrome only if at most one character occur odd no. of times and all other characters must occur even number of times. The following program can be used to check whether a palindrome can be string or not.

void checkPalindrome(string s)
{
vector<int> vec(256,0);    //Vector for all ASCII characters present.
for(int i=0;i<s.length();++i)
{
    vec[s[i]-'a']++;
}
int odd_count=0,flag=0;
for(int i=0;i<vec.size();++i)
{
    if(vec[i]%2!=0)
        odd_count++;
    if(odd_count>1)
    {
        flag=1;
         cout<<"Can't be palindrome"<<endl;
        break;  
    }
}
if(flag==0)
    cout<<"Yes can be palindrome"<<endl;
}

Solution 10:[10]

With O(n) complexity .

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace PallindromePemutation
{
    class charcount
    {
        public char character { get; set; }
        public int occurences { get; set; }
    }
    class Program
    {
        static void Main(string[] args)
        {

            List<charcount> list = new List<charcount>();
            charcount ch;
            int count = 0;
            char[] arr = "travel".ToCharArray();
            for (int i = 0; i < arr.Length; i++)
            {
                charcount res = list.Find(x => x.character == arr.ElementAt(i));
                if (res == null)
                {
                    ch = new charcount();
                    ch.character = arr.ElementAt(i);
                    ch.occurences = 1;
                    list.Add(ch);
                }
                else
                {
                    charcount temp=  list.Find(x => x.character == arr.ElementAt(i));
                    temp.occurences++;
                }
            }
            foreach (var item in list)
            {
                if (!(item.occurences % 2 == 0))
                {
                    count++;
                }
            }
            if (count > 1)
            {
                Console.WriteLine("false");
            }
            else
            {
                Console.WriteLine("true");
            }
            Console.ReadKey();
        }
    }
}

Solution 11:[11]

If we don't care case sensitivity of characters and spaces within a string, then a sample solution in C# by using Dictionary can be like :

    private static bool IsPalindromePermutation(string inputStr)
    {
        // First, check whether input string is null or whitespace.
        // If yes, then return false.
        if (string.IsNullOrWhiteSpace(inputStr))
            return false;

        var inputDict = new Dictionary<char, int>();

        // Big/small letter is not important
        var lowerInputStr = inputStr.ToLower();

        // Fill input dictionary
        // If hit a space, then skip it
        for (var i = 0; i < lowerInputStr.Length; i++)
        {
            if (lowerInputStr[i] != ' ')
            {
                if (inputDict.ContainsKey(lowerInputStr[i]))
                    inputDict[lowerInputStr[i]] += 1;
                else
                    inputDict.Add(lowerInputStr[i], 1);
            }
        }

        var countOdds = 0;
        foreach(var elem in inputDict)
        {
            if(elem.Value % 2 != 0)
                countOdds++;
        }

        return countOdds <= 1;
    }

Solution 12:[12]

We can acheive this via collections also

String name = "raa";
        List<Character> temp = new ArrayList<>(name.chars()
                .mapToObj(e -> (char) e).collect(Collectors.toList()));

        for (int i = 0; i < temp.size(); i++) {
            for (int j = i + 1; j < temp.size(); j++) {
                if (temp.get(i).equals(temp.get(j))) {
                    temp.remove(j);
                    temp.remove(i);
                    i--;
                }

            }

        }

        if (temp.size() <= 1) {
            System.out.println("Pallindrome");
        } else {
            System.out.println(temp.size());
            System.out.println("Not Pallindrome");
        }
    }

Solution 13:[13]

This is my solution

public static void main(String[] args) {
    List<Character> characters = new ArrayList<>();
    Scanner scanner = new Scanner(System.in);
    String input = scanner.nextLine();
    for (int i = 0; i < input.length(); i++){
        char val = input.charAt(i);
        if (characters.contains(val)){
            characters.remove(characters.indexOf(val));
        } else{
            characters.add(val);
        }
    }
    if (characters.size() == 1 || characters.size() == 0){
        System.out.print("Yes");
    } else{
        System.out.print("No");
    }
}

Solution 14:[14]

That 's my solution. The string could contain several words with spaces, such as
Input: Tact Coa Output true Input: Tact Coa vvu Output: false

public static boolean checkForPalindrome(String str) {
    String strTrimmed = str.replaceAll(" ","");
    System.out.println(strTrimmed);
    char[] str1 = strTrimmed.toCharArray();

    for (int i = 0; i < str1.length; i++) {
        str1[i] = Character.toLowerCase(str1[i]);
    }

    Arrays.sort(str1);
    String result = new String(str1);
    System.out.println(result);
    int count = 0;
    for (int j = 0; j < str1.length; j += 2) {
    if (j != str1.length-1) {
        if (str1[j] != str1[j+1]) {
            count++;
            j++;

        }
    } else {
        count++;
    }
   }        
    if (count > 1) return false;
    else return true;
}

Solution 15:[15]

Question: Can a String become a palindrome? Method1: count of characters IN Java :

public class TEST11 {

    public static void main(String[] args) {
        String a = "Protijayi";

        int[] count = new int[256];
        Arrays.fill(count, 0);
        for (int i = 0; i < a.length(); i++) {
            char ch = a.charAt(i);
            count[ch]++;
        } // for
            // counting of odd letters
        int odd = 0;
        for (int i = 0; i < count.length; i++) {
            if ((count[i] & 1) == 1) {
                odd++;
            }

        } // for
        if (odd > 1) {
            System.out.println("no");
        } else {
            System.out.println("yes");
        }

    }

}

IN Python:

def fix (a):
    count = [0] * 256
    for i in a: count[ord(i)] += 1
    # counting of odd characters
    odd = 0 
    for i in range(256): 
        if((count[i] & 1) == 1): odd += 1

    if(odd > 1):print("no")
    else:print("yes")


a = "Protijayi"

fix(a)

Method 2 : Use of HashSet In Java:

public class TEST11 {

    public static void main(String[] args) {

        String a = "Protijayi";
        Set<Character> set = new HashSet<>();
        for (char ch : a.toCharArray()) {

            if (set.contains(ch)) {
                set.remove(ch);
            }
            set.add(ch);
        } // for

        if (set.size() <= 1) {
            System.out.println("yes can be a palindrome");
        } else {
            System.out.println("no");
        }

    }

}

Solution 16:[16]

Swift example for this question.

var str = "mmoosl"
extension String {
func count(of needle: Character) -> Int {
    return reduce(0) {
        $1 == needle ? $0 + 1 : $0
    }
}
}



func canBeTurnedIntoAPalinpolyString(_ polyString: String) -> Bool {
var centerUsed = false
var center = Character("a")
for i in polyString {
    let count  = polyString.count(of: i)
    if count == 1 && !centerUsed {
        center = i
        centerUsed = true
    } else {
        if count % 2 != 0 {
            return false
        }
    }
}
 return true
}

print(canBeTurnedIntoAPalinpolyString(str))

Solution 17:[17]

Java

private static boolean isStringPalindromePermutation(String input) {

    if(input == null) return false;

    if(input.isEmpty()) return false;

    int checker = 0;
    for (int i = 0; i < input.length(); i++) {
        int character = input.charAt(i) - 'a';

        int oneShiftedByNumberInCharacter = 1 << character;

        int summaryAnd = checker & oneShiftedByNumberInCharacter;
        if ( summaryAnd > 0 ) {
            int revertToShiftedByChar = ~oneShiftedByNumberInCharacter;
            checker = checker & revertToShiftedByChar;
        } else {
            checker |= oneShiftedByNumberInCharacter;
        }
    }
    if ( input.length() % 2 == 0 ) {
        if ( checker == 0) {
            return true;
        }
        else return false;
    } else {
        int checkerMinusOne = checker-1;
        if((checkerMinusOne & checker) == 0){
            return true;
        }else{
            return false;
        }
    }

}

Solution 18:[18]

Why use a suffix tree or any other data structure?

The basic requirement of a palindromic string is the frequency of all characters must be even or only one character can have odd frequency.

Example :-

Input : aabbaa

Output : frequency of a is 4 and b is 2 (both even)

Input : xxzyzxx

Output : frequency of x is 4, z is 2 and y=1 (only 1 odd)

Sample code for better understanding :

bool ispalin(string str)                      //function to check
{ 
int freq[26] = {0};               //to store frequency of character here i am
                                          // considering only lower case letters 
for (int i = 0; str.length();  i++) 
    freq[str[i]]++; 
int odd = 0; 
for (int i = 0; i < 26; i++)      //Count odd occurring characters 
{ 
    if (freq[i] & 1)                       //checking if odd
        odd++; 
    if (odd > 1)                          //if number of odd freq is greater than 1
        return false; 
}  
return true;                             //else return true
} 

Solution 19:[19]

python code to check whether a palindrome can be formed from given string or not:

test_str = input('enter any string = ')
count = 0 
for item in set(test_str):
    if test_str.count(item)%2 != 0:
        count+=1 
if (count>1):
    print(" palindrome cannot be formed")
else:
    print(" palindrome can be formed")

Please try this code if any issue please comments

Solution 20:[20]

More efficient implementation - Java

boolean palindromeRearranging(String inputString) {
    Map<Character, Integer> charsCount = new HashMap<Character, Integer>();
    for(char c : inputString.toCharArray()){
        charsCount.compute(c, (key, val) ->  val == null ? 1 : val + 1);
    }
    List<Integer> result = new ArrayList<>();
    charsCount.forEach((k, v) -> {
        if(v % 2 != 0){
            result.add(v);
        }
    });
    return (result.size() == 0 || result.size() == 1);
}

Solution 21:[21]

Here is my code :

 boolean palindromeRearranging(String inputString) {
        HashMap<Character,Integer> stCount=new HashMap<>();
        for(int i=0;i<inputString.length();i++){
            stCount.put(inputString.charAt(i),0);
        }
        for(int i=0;i<inputString.length();i++){
            int c= stCount.get(inputString.charAt(i));
            stCount.put(inputString.charAt(i),++c);
        }
        int c=0;
        for (Map.Entry<Character,Integer> entry : stCount.entrySet()){
            if(entry.getValue()%2!=0){
                c++;
                if(c>1){
                    return false;
                }
            }   
        }
        return true;
    }

Solution 22:[22]

JS solution:

function solution(inputString) {
  const arr = inputString.split('');
  let hasCoupleList = arr.map( (el) =>  arr.filter( (el1) => el1 == el).length % 2 == 0).filter( (el) => el == false).length;
  return (arr.length % 2 == 0)
    ? hasCoupleList == 0
    : hasCoupleList == 1;
}