web-dev-qa-db-fra.com

Vérifier si une permutation d'une chaîne peut devenir un palindrome

Ecrivez une méthode pour vérifier si une chaîne remplit les conditions préalables pour devenir un palindrome.

Par exemple:

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

Je pense à cette approche:

  1. Créez un arbre de suffixe pour toute permutation de T tel que T $ Reverse (T) #
  2. Vérifier toutes les permutations pour le même noeud

Est-ce que je manque quelque chose?

6
user5080124

Vraiment, tout ce que vous cherchez, c’est que toutes les lettres (ou toutes les lettres sauf une) soient jumelées. Tant qu'ils le seront, ils pourront être transformés en palindrome.

Donc, ce serait quelque chose comme ...

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;
}

Ce n'est pas le plus efficace (compter les lettres autant de fois qu'il les rencontre, même si elles ont déjà été comptées), mais cela fonctionne.

3
Matthew

Tout ce que vous avez à faire, c'est de vérifier qu'il y a au plus un caractère avec un nombre impair d'occurrences. Voici un exemple Java:

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 (oui - elles sont ordonnées pour avoir un sens, mais elles sont numérotées par ordre chronologique):
La mise en œuvre ci-dessus présente une inefficacité intrinsèque. Je ne pense pas que la première itération sur la chaîne puisse être évitée, mais il n'y a pas de vraie raison de garder un compte de toutes les occurrences - c'est assez pour garder une trace de ceux qui ont un compte impair. Pour ce cas d'utilisation, il suffit de garder trace de chaque caractère rencontré (par exemple, avec une variable Set) et de le supprimer lorsque nous le rencontrons à nouveau. Dans le pire des cas, où tous les caractères de la chaîne sont différents, les performances sont comparables, mais dans le cas habituel, où il existe plusieurs occurrences de chaque caractère, cette implémentation améliore à la fois la complexité temporelle et mémoire de la maintenant réduite à une seule condition) de façon dramatique:

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 (oui - elles sont ordonnées pour avoir un sens, mais elles sont numérotées par ordre chronologique):
Java 8 fournit une API de streaming fluide qui pourrait être utilisée pour créer une implémentation semblable aux liners Python ci-dessous:

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;
}

MODIFIER:
Les fonctions intégrées et les capacités de compréhension de Python rendent cette option trop attrayante pour ne pas publier cette solution one-liner. C'est probablement moins efficace que celui de Java, mais il est assez élégant:

from collections import Counter

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

EDIT2:
Ou encore, une approche encore plus propre proposée par @DSM dans les commentaires:

from collections import Counter

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

Au lieu de compter le nombre de fois que chaque lettre se produit, une autre approche permet de savoir si une lettre est survenue un nombre impair ou pair. Si une lettre est survenue un nombre pair de fois, vous n’avez pas à vous en soucier, vous devez seulement garder une trace des occurrences impaires d’un ensemble. En 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;
}
6
Teepeemm
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]
3
Jonathan Li

Si je comprends bien votre question, voici comment je le comprends:

Si la chaîne d'entrée peut être réorganisée en un palindrome, indiquez "True", sinon indiquez "False".

Ensuite, vous pouvez utiliser ces règles simples:

  1. Si la longueur est paire, chaque caractère unique de l'entrée doit apparaître deux fois.
  2. Si la longueur est impair, chaque caractère unique, sauf un, doit apparaître plusieurs fois de suite. Un seul caractère est autorisé à pas se produire un multiple de 2 fois.

Donc pour les 3 exemples donnés:

"mmo", longueur impaire, m apparaît deux fois (multiple de 2), o une fois (pas un multiple de 2), donc True.

"yakak", longueur irrégulière, a apparaît deux fois (multiple de 2), k apparaît deux fois (multiple de 2), y apparaît une fois (pas un multiple de 2), donc True.

"voyage", plus d'un caractère ne se produit pas un multiple de 2, donc False.

Exemples supplémentaires:

"mmorpg", seulement m se produit un multiple de 2, le reste une seule fois, donc False.

"mmom", aucun caractère ne correspond à un multiple de 2, plus d'un caractère "pas un multiple de 2 fois", donc False.

À ce stade, vous devez comprendre que si un seul caractère est autorisé à apparaître une fois non multiple, vous pouvez ignorer la longueur. Une chaîne de longueur paire aura soit 2 caractères ou plus, soit un nombre de fois non multiple, soit aucun.

La règle finale devrait donc être la suivante:

Si au plus 1 caractère unique apparaît une fois non multiple de 2, le résultat est True sinon le résultat est False.

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

J'ai atteint la solution ci-dessous aujourd'hui (python). Je pense que c'est lisible et que, du point de vue des performances, c'est vraiment bon.

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

Nous comptons essentiellement le nombre d'occurrences de chaque caractère dans la chaîne "Word", obtenons le reste de la division par 2, les additionnant et vérifiant si vous en avez au plus 1.

L'idée est que vous devez associer tous les caractères, sauf potentiellement pour un (le milieu).

1
Mawkee

Mon idée est la suivante: si le nombre de lettres avec un nombre impair est égal à un et que le reste a un nombre égal, un palindrome est possible. Voici mon programme en 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")
0
Arindam Roychowdhury

C'est ma 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");
    }
}
0
Anand Mishra

Question: Une chaîne peut-elle devenir un palindrome? Méthode 1: nombre de caractères EN 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");
        }

    }

}

EN 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)

Méthode 2: Utilisation de HashSet En 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");
        }

    }

}
0
Soudipta Dutta

Si nous ne nous soucions pas de la casse des caractères et des espaces d'une chaîne, un exemple de solution en C # à l'aide de Dictionary peut ressembler à:

    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;
    }
0
ersegun

Toute chaîne ne peut être palindrome que si au plus un caractère est impair impair. nombre de fois et tous les autres caractères doivent apparaître même nombre de fois. Le programme suivant peut être utilisé pour vérifier si un palindrome peut être une chaîne ou non.

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;
}
0
Prashant Shubham

Avec O(n) complexité.

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();
        }
    }
}
0
hussain

C'est ma solution. La chaîne peut contenir plusieurs mots avec des espaces, tels que
Entrée: Tact Coa Sortie true Entrée: Tact Coa vvu Sortie: 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;
}
0
Loay

Nous pouvons y arriver via des collections également

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");
        }
    }
0
Rahul Singh