检查字符串的排列是否可以成为回文

时间:2015-07-04 19:55:02

标签: string algorithm palindrome

  

编写一个方法来测试字符串是否满足成为回文的前提条件。

     

例如:

$token = $this->securityContext->getToken();
if (empty($token)) {
    return [];
}
$user = $token->getUser();
if (empty($user)) {
    return [];
}
$roles = $user->getRoles();

我正在考虑这种方法:

  1. 为T的所有排列设置后缀树,使得T $ Reverse(T)#
  2. 检查同一节点的所有排列
  3. 我错过了什么吗?

20 个答案:

答案 0 :(得分:17)

您需要做的就是检查最多只有一个字符出现次数奇数。这是一个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提供了一个流畅的流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;
}

编辑:
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

答案 1 :(得分:6)

不是计算每个字母出现的次数,而是另一种方法跟踪字母是否发生了奇数或偶数次。如果一个字母发生了偶数次,你不需要担心它,只需要跟踪一组中的奇数事件。在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;
}

答案 2 :(得分:3)

你真正想要的就是如果所有(或除了一个)字母都配对了。只要它们是,那么它们就能变成回文。

所以它会像......

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

这不是效率最高的(即使它们已被计算在内,也会计算出它们的次数,但是它确实有效。)

答案 3 :(得分:3)

如果我正确理解你的问题,我就是这样理解的:

  

如果输入字符串可以重新排列成回文,则输出“True”,否则输出“False”。

然后你可以使用这些简单的规则:

  1. 如果长度是偶数,则输入中的每个唯一字符必须出现2次的倍数。
  2. 如果长度是奇数,则除了一个之外的每个唯一字符必须出现2次的倍数。只允许1个字符出现2次的倍数。
  3. 因此对于3个给出的例子:

    “mmo”,奇数长度,m出现两次(2的倍数),o出现一次(不是2的倍数),所以True

    “yakak”,奇数长度,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

答案 4 :(得分:3)

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]

答案 5 :(得分:1)

<?xml version="1.0" encoding="utf-8"?>
<fragment xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:map="http://schemas.android.com/apk/res-auto"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:id="@+id/map_fragment"
    android:name="com.google.android.gms.maps.SupportMapFragment"
    map:uiRotateGestures="false"
    map:uiTiltGestures="false"
    map:uiScrollGestures="false"
    map:uiZoomGestures="false"
    map:cameraZoom="12"
    map:cameraTargetLat="-35"
    map:cameraTargetLng="150"
    />

答案 6 :(得分:1)

我今天达到了解决方案(python)。我认为它是可读的,而且性能方面非常好。

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

我们基本上计算字符串“word”中每个字符的出现次数,将除法的余数除以2,将它们相加并检查是否最多有1个字符。

这个想法是你需要配对所有角色,除了可能是一个(中间的)。

答案 7 :(得分:0)

更高效的实现 - 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);
}

答案 8 :(得分:0)

用于检查是否可以从给定字符串形成回文的python代码:

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

请尝试此代码,如果有任何问题请评论

答案 9 :(得分:0)

为什么使用后缀树或任何其他数据结构?

回文字符串的基本要求是所有字符的出现频率 必须为偶数 ,否则只有一个字符可以具有奇数频率

示例:-

输入:aabbaa

Output :a的频率为4,b的频率为2(均为偶数)

输入:xxzyzxx

输出:x的频率为4,z为2,y = 1(仅1个奇数)

示例代码以更好地理解:

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
} 

答案 10 :(得分:0)

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

}

答案 11 :(得分:0)

此问题的快速示例。

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

答案 12 :(得分:0)

问题:字符串可以成为回文吗? 方法1:字符数 在爪哇:

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

    }

}

答案 13 :(得分:0)

这是我的解决方案。该字符串可以包含多个带空格的单词,例如
输入:Tact Coa 输出为真 输入:Tact Coa vvu 输出: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;
}

答案 14 :(得分:0)

这是我的解决方案

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

答案 15 :(得分:0)

我们也可以通过收藏来实现这个目标

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

答案 16 :(得分:0)

如果我们不关心字符串中字符和空格的区分大小写,那么使用Dictionary在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;
    }

答案 17 :(得分:0)

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

答案 18 :(得分:0)

只有当最多一个字符出现奇数时,任何字符串都可以是回文。时间和所有其他字符必须发生偶数次。以下程序可用于检查回文是否可以串。

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

答案 19 :(得分:0)

我的想法是,如果奇数的字母数是1,其余的都是偶数,那么可能是回文。这是我的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")