Проверьте, может ли перестановка строки стать палиндромом

напишите метод, чтобы проверить, соответствует ли строка предварительным условиям, чтобы стать палиндромом.

например:

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

Я думаю об этом подходе:

  1. сделайте дерево суффиксов для всех перестановок T таким, чтобы T$Reverse (T)#
  2. проверьте все перестановки для одного и того же узла

Я что-нибудь пропустил?

16 ответов


на самом деле все, что вы ищете, если все (или все, кроме одной) буквы на пары. Пока они есть, тогда они смогут быть превращены в палиндром.

таким образом, это было бы что-то вроде...

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

Это не самый эффективный (он подсчитывает буквы столько раз, сколько встречается с ними, даже если они уже подсчитаны), но он работает.


все, что вам нужно сделать, это проверить, что там более одного символа с нечетным количеством вхождений. Вот пример 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 (да-они упорядочены, чтобы иметь смысл, но пронумерованы хронологическим порядком):
Вышеуказанная реализация имеет встроенную неэффективность. Я не думаю, что первой итерации по строке можно избежать, но нет никакой реальной причины вести счет всех вхождений - достаточно просто отслеживать те, у кого нечетные рассчитывать. Для этого использования достаточно отслеживать каждый символ, с которым мы сталкиваемся (например, с Set), и удалите его, когда мы столкнемся с ним снова. В худшем случае, когда все символы в строке разные, производительность сопоставима, но в общем случае, когда есть несколько вхождений каждого символа, эта реализация улучшает как время, так и сложность памяти второго цикла (который теперь сводится к одному условию) драматично:

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 (да-они упорядочены, чтобы иметь смысл, но пронумерованы хронологическим порядком):
Java 8 предоставляет fluent streaming API, который может быть использован для создания реализации, подобной однострочным Python ниже:

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 и возможности понимания делают это слишком привлекательным, чтобы не публиковать это одно линейное решение. Это, вероятно, менее эффективно, чем вышеупомянутый Java, но довольно элегантно:

from collections import Counter

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

EDIT2:
Или еще более чистый подход, предложенный @DSM в комментариях:

from collections import Counter

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

вместо того, чтобы считать, сколько раз каждая буква происходит, другой подход отслеживает, произошло ли письмо нечетное или четное число раз. Если письмо возникло четное количество раз, вам не нужно беспокоиться об этом, а нужно только отслеживать нечетные вхождения в наборе. В 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;
}

если я правильно понимаю ваш вопрос, вот как я его понимаю:

если входную строку можно переставить в палиндром, выведите "True", в противном случае выведите"False".

затем вы можете использовать эти простые правила:

  1. если длина четная, каждый уникальный символ во входных данных должен произойти несколько 2 раза.
  2. если длина нечетная, каждый уникальный символ, кроме одного, происходят в кратно 2 раза. Только 1 символ разрешено не происходят несколько 2 раза.

Итак, для 3 приведенных примеров:

" mmo", нечетная длина,m происходит дважды (кратно 2),o происходит один раз (не кратным 2), так True.

"якак", нечетная длина,a происходит дважды (кратно 2),k происходит дважды (кратно 2),y происходит один раз (не кратным 2) , так True.

"путешествие", более одного символа не встречается кратно 2, поэтому False.

дополнительные примеры:

"mmorpg", только m происходит кратно 2, остальные только один раз, так False.

"mmom", никаких символов не происходит кратно 2, более одного символа происходит "не кратно 2 раза", поэтому False.

на данный момент Вы должны понимать, что если только 1 символ может произойти не несколько-из-2 раз, то вы можете игнорировать длина. Строка с четной длиной будет иметь либо 2, либо более символов, встречающихся не кратно-2 раза, либо вообще ни одного.

Итак, последнее правило должно быть таким:

если не более 1 уникального символа происходит не несколько-из-2 раз на входе, выход True в противном случае выводится False.


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]

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

Я достиг решения ниже сегодня (python). Я думаю, что это читабельно, и с точки зрения производительности это действительно хорошо.

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

мы в основном подсчитываем количество вхождений каждого символа в строке "word", получая остаток деления на 2, суммируя их все и проверяя, есть ли у вас не более 1 из них.

идея в том, что вам нужно иметь все символы в паре, за исключением потенциально одного (среднего).


вы можете сохранить запущенный xor букв в строке. Если результат равен 0, то все символы имеют пару. Если результат представляет символ, существующий в строке, то все буквы имеют пару, кроме одной.

используя это правило, мы можем определить, является ли перестановка строки палиндромом:

def can_be_palindrome(string):
    char_set = {}
    xor_result = 0
    for c in string:
        if c not in char_set:
            char_set[c] = 1
        xor_result ^= ord(c)
    return xor_result == 0 or chr(xor_result) in char_set

моя идея заключается в том, что если количество букв с нечетным числом равно одному, а остальные имеют четный счет, палиндром возможен..Вот моя программа на 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")

любая строка может быть палиндромом, только если не более одного символа встречается нечетное нет. раз и все остальные символы должны встречаться четное количество раз. Следующая программа может использоваться для проверки того, может ли палиндром быть строковым или нет.

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

со сложностью O(n).

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

Если нас не волнует чувствительность к регистру символов и пробелов в строке, то пример решения в C# с помощью словаря может быть таким:

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

мы можем достичь этого через коллекции также

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

Это мое решение

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

Это мое решение. Строка может содержать несколько слов с пробелами, например
Вход: Такт Coa Вывод true Вход: Tact Coa vvu Вывод: ложь

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

вопрос: Может ли строка стала палиндромом? Method1: количество символов В 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");
        }

    }

}

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

Метод 2: Использование HashSet В 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");
        }

    }

}