Created
September 16, 2011 08:47
-
-
Save tomviner/1221595 to your computer and use it in GitHub Desktop.
Anagram of Palindrome
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# -*- coding: utf-8 -*- | |
""" | |
1) A string is a palindrome if it reads the same from left-to-right as it does right-to-left. | |
e.g “nolemonnomelon”, “racecar” & “neveroddoreven” are all palindromes. | |
A string is an anagram of another string if it consists of exactly the same characters but in another order. | |
e.g The string “carrace” is an anagram of “racecar”. | |
Write a function `def is_anagram_of_palindrome(str):` | |
such that it returns True if the string str is an anagram of a palindrome, and otherwise returns False. | |
You may assume that str contains only lowercase characters a-z and is not empty. | |
e.g Given str = “carrace” the function should return True as it is an anagram of the palindrome “racecar”. | |
Given str = “tangent” the function should return False as while it is an anagram, | |
it is not possible that it is an anagram of a palindrome. | |
We are not dealing with English words here, “bbcbb” is still a palindrome. | |
""" | |
def is_anagram_of_palindrome(str): | |
""" | |
Note: 'aa' is considered to have no anagrams, as 'aa' (other way round) is the same string. | |
Also: It's generally best not to use the python string constructor as a variable name :-) | |
>>> is_anagram_of_palindrome('') | |
False | |
>>> any(is_anagram_of_palindrome(n*'a') for n in range(1, 10)) # all already ordered as only palindrome | |
False | |
>>> any(is_anagram_of_palindrome(n*'a' + 'b' + n*'a') for n in range(1, 10)) # all already ordered as only palindrome | |
False | |
>>> is_anagram_of_palindrome('ab') | |
False | |
>>> is_anagram_of_palindrome('aab') | |
True | |
>>> is_anagram_of_palindrome('aba') # already ordered as only palindrome | |
False | |
>>> is_anagram_of_palindrome('abab') | |
True | |
>>> is_anagram_of_palindrome('abba') # has one other palindrome | |
True | |
>>> is_anagram_of_palindrome('abcba') # has one other palindrome | |
True | |
>>> is_anagram_of_palindrome('aabc') | |
False | |
>>> is_anagram_of_palindrome('aaabb') | |
True | |
>>> is_anagram_of_palindrome('aaabc') | |
False | |
>>> is_anagram_of_palindrome('aaaabb') | |
True | |
>>> is_anagram_of_palindrome('aaaabbc') | |
True | |
>>> is_anagram_of_palindrome('tangent') | |
False | |
>>> is_anagram_of_palindrome('nolemonnomelon') # already palindrome but others possible | |
True | |
""" | |
letter_counts = [str.count(ch) for ch in set(str)] | |
num_odd_letters = len([n for n in letter_counts if n%2]) | |
num_even_letters = len(letter_counts) - num_odd_letters | |
# characters in a palindromes can pair off from the ends, leaving 0 or 1 | |
# characters in the middle. Any middle character always appears an odd number | |
# of times in the string | |
can_form_palindrome = num_odd_letters <= 1 | |
# a palindrome can only form another palindrome if it contains more than | |
# one type of letter to swap positions (eg abba --> baab), excluding a possible | |
# centre letter in odd length strings | |
is_only_palindrome = (num_even_letters <= 1) if (str==str[::-1]) else False | |
return can_form_palindrome and not is_only_palindrome | |
if __name__ == '__main__': | |
import doctest | |
doctest.testmod() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
elegant solution.
may I suggest you to replace parameter str with something else as it is a Python builtin function?