3

Hello i´ve been trying to form palindromes from this input:

String[] text ={"ivcci", "oyotta", "cecarar","bbb","babbbb"};
getPalindrome(text);

and i need to rearrange all words in array to produce this output

civic
-1
rececar
bbb
bbabb

the method expects to receive an array of Strings like

public static String getPalindrome(String[] text){}

"returning -1 means i.g "oyotta" in array can´t form a palíndrome

i´ve been testing this code and it works but i.g "cecarar" is not producing "racecar", as im a bit new in java i used an String intead an array of Strings, can anybody help to write this code properly please?

Thanks a lot!

public static String getPalindrome(String s) {

    if (s == null)
        return null;
    Map<Character, Integer> letters = new HashMap<Character, Integer>();

    for (int i = 0; i < s.length(); i++) {
        char c = s.charAt(i);
        if (!letters.containsKey(c))
            letters.put(c, 1);
        else
            letters.put(c, letters.get(c) + 1);
    }

    char[] result = new char[s.length()];
    int i = 0, j = result.length - 1;
    Character middle = null;
    for (Entry<Character, Integer> e : letters.entrySet()) {
        int val = e.getValue();
        char c = e.getKey();

        if (val % 2 != 0) {
            if (middle == null && s.length() % 2 != 0) {
                middle = c;
                val--;
            } else
                return "-1";
        }
        for (int k = 0; k < val / 2; k++) {
            result[i++] = c;
            result[j--] = c;
        }
    }
    if (middle != null)
        result[result.length / 2] = middle;
    return new String(result);
}
nem035
  • 34,790
  • 6
  • 87
  • 99

2 Answers2

2

In order for a set of characters to be able to produce a palindrome, only one of the letters can be repeated an odd number of times, so you can first weed that out.

Without writing actual code for you, here is the algorithm I would use:

Create a map of characters to a counter. Possible to do int[] counts = new int[26]; Go through each character in the input string, and increment the count: ++counts[Character.toLower(c)-'a']; Then go through each character, and see if its odd if (counts[i] & 1 != 0) { if (oddIndex != -1) { return -1; } oddIndex=i; } This will return -1 if there is two or more odd counts. Then, you can create a StringBuilder, and start with the oddIndex in the middle, if it exists. Then go through the counts, and add count[i]/2 to the front and back of your string builder.

That'll give you a symmetric string from the original inputs.

Now, if you actually need words, then you'll have to have a dictionary of palindromes. You can actually preprocess all the palindromes to have a map of "sorted character string"=>"palindrome"

class PalindromeChecker
{
    final Map<String, String> palindromes = new HashMap<String, String>();

    public PalindromeChecker(Iterable<String> allPalindromes) {
        for (String palindrome: allPalindromes) {
           char[] chars = palindrome.getChars();
           Arrays.sort(chars);
           palindromes.put(String.valueOf(chars), palindromes);
        }
    }

    public String getPalindrome(String input) {
           char[] chars = input.getChars();
           Arrays.sort(chars);

           return palindromes.get(String.valueOf(chars));
    }
}
Daniel
  • 4,481
  • 14
  • 34
1

As other users pointed out, a string can be rearranged as a palindrome only if there is at most one character that appears an odd number of times.

Once you have confirmed that a string can be converted to a palindrome, you can construct the palindrome as follows (this is just one of many methods of course):

  • place at the sides of the string all the pairs of characters that you can get
  • place at the middle of the string the single character that is left out, in case there is such a character.

Example:

public class Palindromes {

    public static void main(String[] args) {
        String[] text = {"ivcci", "oyotta", "cecarar","bbb","babbbb"};
        for(String str : text){
            evaluatePalindrome(str);
        }
    }

    private static void evaluatePalindrome(String str){
        PalindromeCandidate pc = new PalindromeCandidate(str);
        if(pc.isPalindrome()){
            System.out.println(pc.getPalindrome());
        } else {
            System.out.println("-1");
        }
    }
}
public class PalindromeCandidate {

    private final CharacterCount characterCount;

    public PalindromeCandidate(String originalString) {
        this.characterCount = new CharacterCount(originalString);
    }

    public boolean isPalindrome(){
        Collection<Integer> counts = characterCount.asMap().values();
        int oddCountOccurrences = 0;
        for(Integer count : counts){
            oddCountOccurrences += (count%2);
        }
        return (oddCountOccurrences <= 1);
    }

    public String getPalindrome(){
        if(!isPalindrome()){
            throw new RuntimeException("Cannot be rearranged as a palindrome.");
        }
        Map<Character, Integer> counts = characterCount.asMap();
        StringBuilder leftSide = new StringBuilder();
        StringBuilder middle = new StringBuilder();
        for(Character ch : counts.keySet()){
            int occurrences = counts.get(ch);
            while(occurrences > 1){
                leftSide.append(ch);
                occurrences -= 2;
            }
            if(occurrences > 0){
                middle.append(ch);
            }
        }
        StringBuilder rightSide = new StringBuilder(leftSide).reverse();
        return leftSide.append(middle).append(rightSide).toString();
    }
}
/**
 * Thin wrapper around a Map<Character, Integer>. Used for counting occurences
 * of characters.
 */
public class CharacterCount {

    private final Map<Character, Integer> map;

    public CharacterCount(String str) {
        this.map = new HashMap<>();
        for(Character ch : str.toCharArray()){
            increment(ch);
        }
    }

    private void increment(Character ch){
        this.map.put(ch, getCount(ch) + 1);
    }

    private Integer getCount(Character ch){
        if(map.containsKey(ch)){
            return map.get(ch);
        } else {
            return 0;
        }
    }

    public Map<Character, Integer> asMap(){
        return new HashMap<>(map);
    }
}
abl
  • 5,970
  • 4
  • 25
  • 44