找出anagram是否是回文的最佳算法是什么?

时间:2011-01-07 17:29:01

标签: algorithm language-agnostic

在这个问题中,我们只考虑小写英文字母(a-z)字符串。

如果字符串从左到右从右到左遍历时具有完全相同的字符序列,则该字符串是回文。例如,以下字符串是回文:

“皮艇”

“codilitytilidoc”

“neveroddoreven”

字符串A是字符串B的字谜,如果它由完全相同的字符组成,但可能是另一种顺序。例如,以下字符串是彼此的字谜:

A =“mary”B =“army”A =“rocketboys”B =“octobersky”A =“codility”B =“codility”

写一个函数

int isAnagramOfPalindrome(String S);

如果字符串s是某些回文的字谜,则返回1,否则返回0.

例如,你的函数应该为参数“dooernedeevrvn”返回1,因为它是回文“anoddoddoreven”的字谜。对于参数“aabcba”,您的函数应返回0。

13 个答案:

答案 0 :(得分:12)

'算法'对它来说太大了。

如果每个字符在该组中出现偶数次(可能除了一个字符),您可以从给定的字符集构造回文。
对于任何其他集合,您可以轻松地显示没有回文存在。

两种情况下的证明都很简单,但如果不清楚,请告诉我。

答案 1 :(得分:3)

在回文中,每个角色必须有一个自身的副本,一个“双胞胎”,在字符串的另一边,除了中间字母,可以作为自己的双胞胎。

您寻找的算法将创建一个长度为26的数组,每个小写字母一个,并开始计算字符串中的字符数,将数字n的数量放在数组的索引n 。然后,它将通过数组并计算奇数的字符数(因为一个字母没有双胞胎)。如果此数字为0或1,则将该单个奇数字母放在中心,并且很容易生成回文。否则,不可能生成一个,因为不存在双胞胎的两个或更多字母,并且它们不能同时位于中心。

答案 2 :(得分:1)

我想出了这个Javascript解决方案。 这个解决方案是基于这样一个前提:当一个字符串是一个回文的字谜时,当且仅当一个字符出现奇数次时才会出现。

function solution(S) {
    var retval = 0;
    var sorted = S.split('').sort(); // sort the input characters and store in 
                                     // a char array
    var array = new Array();

    for (var i = 0; i < sorted.length; i++) {

        // check if the 2 chars are the same, if so copy the 2 chars to the new
        // array
        // and additionally increment the counter to account for the second char
        // position in the loop.
        if ((sorted[i] === sorted[i + 1]) && (sorted[i + 1] != undefined)) {
            array.push.apply(array, sorted.slice(i, i + 2));
            i = i + 1;
        }
    }

    // if the original string array's length is 1 or more than the length of the
    // new array's length
    if (sorted.length <= array.length + 1) {
        retval = 1;
    }

    //console.log("new array-> " + array);
    //console.log("sorted array-> " + sorted);
    return retval;
}

答案 3 :(得分:1)

我在java中编写了这段代码。我不认为它会是一个好人^^,

 public static int isAnagramOfPalindrome(String str){
     ArrayList<Character> a = new ArrayList<Character>();

     for(int i = 0; i < str.length(); i++){
         if(a.contains(str.charAt(i))){
             a.remove((Object)str.charAt(i));
         }
         else{
             a.add(str.charAt(i));
         }
     }
     if(a.size() > 1)
        return 0;
     return 1;
 }

答案 4 :(得分:1)

算法:

  1. 计算每个角色的出现次数。

  2. 只允许一个出现奇数的字符,因为在回文中,奇数出现的字符的最大数量可以是&#39; 1&#39;。

  3. 所有其他字符应该偶数次出现。

  4. 如果(2)和(3)失败,则给定的字符串不是回文。

答案 5 :(得分:0)

这增加了给出的其他答案。我们希望跟踪所看到的每个字母的数量。如果我们有一个以上的奇数计数,那么我们将无法形成回文。奇数将在中间,但只有一个奇数可以这样做。

我们可以使用hashmap来跟踪计数。查找hashmap是O(1)所以它很快。我们能够在O(n)中运行整个算法。这是代码:

if __name__ == '__main__':
    line = input()

    dic = {}
    for i in range(len(line)):
        ch = line[i]
        if ch in dic:
            dic[ch] += 1
        else:
            dic[ch] = 1

    chars_whose_count_is_odd = 0
    for key, value in dic.items():
        if value % 2 == 1:
            chars_whose_count_is_odd += 1

    if chars_whose_count_is_odd > 1:
        print ("NO")
    else:
        print ("YES")

答案 6 :(得分:0)

我在this question中发布了一个关于复杂性的PHP的简洁解决方案。

class Solution { 

    // Function to determine if the input string can make a palindrome by rearranging it
    static public function isAnagramOfPalindrome($S) {

        // here I am counting how many characters have odd number of occurrences
        $odds = count(array_filter(count_chars($S, 1), function($var) {
            return($var & 1);
        }));
        // If the string length is odd, then a palindrome would have 1 character with odd number occurrences
        // If the string length is even, all characters should have even number of occurrences
        return (int)($odds == (strlen($S) & 1));
    }
}

echo Solution :: isAnagramOfPalindrome($_POST['input']);

它使用内置的PHP函数(为什么不使用),但您可以自己创建,因为这些函数非常简单。首先,count_chars函数生成一个命名数组(python中的字典),其中包含出现在字符串中的所有字符及其出现次数。它可以用这样的自定义函数代替:

$count_chars = array();
foreach($S as $char) {
    if array_key_exists($char, $count_chars) {
        $count_chars[$char]++;
    else {
        $count_chars[$char] = 1;
    }
}

然后,应用具有array_filter函数的count来计算出现奇数的字符数:

$odds = 0;
foreach($count_chars as $char) {
    $odds += $char % 2;
}

然后你只需在return中应用比较(在原始函数的注释中解释)。

return ($odds == strlen($char) % 2)

答案 7 :(得分:0)

这在O(n)中运行。对于所有角色而不是一个,必须是均匀的。可选的奇数字符可以是任何奇数。

e.g。 ABABABA

def anagram_of_pali(str):
    char_list = list(str)
    map = {}
    nb_of_odds = 0

    for char in char_list:
        if char in map:
            map[char] += 1
        else:
            map[char] = 1

    for char in map:
        if map[char] % 2 != 0:
            nb_of_odds += 1

    return True if nb_of_odds <= 1 else False

答案 8 :(得分:0)

你只需计算所有字母并检查是否有奇数字母。如果有多个字母带有奇数,则该字符串不满足上述回文条件  此外,由于具有偶数字母的字符串不能具有带奇数的字母,因此不必检查字符串长度是否为偶数。这需要 O(n)时间复杂度:

以下是javascript中的实施:

function canRearrangeToPalindrome(str)
{
    var letterCounts = {};
    var letter;
    var palindromeSum = 0;
    for (var i = 0; i < str.length; i++) {
        letter = str[i];
        letterCounts[letter] = letterCounts[letter] || 0;
        letterCounts[letter]++;
    }
    for (var letterCount in letterCounts) {
        palindromeSum += letterCounts[letterCount] % 2;
    }

    return palindromeSum < 2;
}

答案 9 :(得分:0)

好吧 - 已经有一段时间了,但是当我在求职面试中被问到这样一个问题时,我需要尝试几行Python。基本思想是,如果有一个字谜是偶数字母的回文,每个字符出现两次(或类似2n次,即计数%2 == 0)。另外,对于奇数个字符,一个字符(中间的一个)可能只出现一次(或不均匀的数字 - 计数%2 == 1)。 我在python中使用了一个集合来获取唯一的字符,然后在条件无法满足后简单地计算和中断循环。示例代码(Python3):

def is_palindrome(s):
  letters = set(s)
  oddc=0
  fail=False

  for c in letters:
      if s.count(c)%2==1:
          oddc = oddc+1

      if oddc>0 and len(s)%2==0:
          fail=True
          break
      elif oddc>1:
          fail=True
          break

  return(not fail)

答案 10 :(得分:-1)

def is_anagram_of_palindrome(S):
    L = [ 0 for _ in range(26) ]
    a = ord('a')
    length = 0
    for s in S:
        length += 1
        i = ord(s) - a
        L[i] = abs(L[i] - 1)
    return length > 0 and sum(L) < 2 and 1 or 0

答案 11 :(得分:-1)

虽然您可以使用给定的技术检测到给定的字符串“S”是候选回文,但它仍然不是很有用。根据给出的实现,

isAnagramOfPalindrome(“rrss”)将返回true但没有实际的回文因为:

回文是一个单词,短语,数字或其他符号或元素序列,其含义可以在正向或反向方向上以相同的方式解释。 (维基百科)

而Rssr或Srrs不是可解释的实际单词或短语。与它的字谜相同。 Aarrdd不是雷达的字谜,因为它不可解释。

因此,给出的解决方案必须通过针对输入的启发式检查来增强,以查看它是否是一个单词,然后验证(通过给出的实现),它完全可以进行回收。然后用n / 2通过收集的桶进行启发式搜索!排列搜索,如果这些是实际的回文而不是垃圾。搜索只有n / 2!而不是n!因为你计算每个重复字母的所有排列,然后你镜像它们(除了可能添加单数枢轴字母)以创建所有可能的回文。

我不同意算法太大了,因为这种搜索可以纯粹递归地进行,或者使用动态编程(对于出现大于2的字母的单词)并且非常简单。

答案 12 :(得分:-1)

以下是一些代码:这与描述算法的最佳答案相同。

  1 #include<iostream>
  2 #include<string>
  3 #include<vector>
  4 #include<stack>
  5 
  6 using namespace std;
  7 
  8 bool fun(string in)
  9 {
 10 int len=in.size();
 11 int myints[len ];
 12 
 13 for(int i=0; i<len; i++)
 14 {       
 15         myints[i]= in.at(i);
 16 }
 17 vector<char> input(myints, myints+len);
 18 sort(input.begin(), input.end());
 19 
 20 stack<int> ret;
 21 
 22 for(int i=0; i<len; i++)
 23 {
 24         if(!ret.empty() && ret.top()==input.at(i))
 25                 {
 26                 ret.pop();
 27                 }
 28         else{
 29         ret.push(input.at(i));
 30         }
 31 }
 32 
 33 return ret.size()<=1;
 34 
 35 }
 36 
 37 int main()
 38 {
 39 string input;
 40 cout<<"Enter word/number"<<endl;
 41 cin>>input;
 42 cout<<fun(input)<<endl;
 43 
 44 return 0;
 45 }