Reputation: 39
Im new to python and im trying to check if any permutation of a string is a palindrome. Here is my code:
def isPal(s):
a = set()
for i in s:
if i in a:
a.remove(i)
else:
if (i != '\n') or (i != ' '):
a.add(i)
if len(a) <= 1:
print(s + ' is a palindrome permutation\n')
else:
print(s + ' is not a palindrome permutation\n')
print(a)
The problem I am having is that it I dont want my set to include spaces or any puncuation thats in the string. Is there any way to only check the letters? For example, the string "Mr. owl ate my Metal worm" shouldnt use the period or spaces when checking if it is a palindrome.
Upvotes: 1
Views: 9857
Reputation: 1
Here I thought of a simple easy to understand python solution. I am making a list of characters whose count comes as odd. If only 1 char is odd then it can fall in between of all the characters thus making it palindrome. Number of odds greater than 1 will make it a non palindrome string.
def isPermutationOfPalindrome(phrase): #solution in O(l) where l is the length of phrase
phrase = phrase.lower()
odd_chars = []
for rec in phrase:
if rec!=' ':
if rec not in odd_chars:
odd_chars.append(rec)
else:
odd_chars.remove(rec)
if(len(odd_chars)<=1):
return True
return False
print(isPermutationOfPalindrome("Tact Coa"))
Tracking of Code:
t --> odd_chars = ['t']
a --> odd_chars = ['t', 'a']
c --> odd_chars = ['t', 'a', 'c']
t --> odd_chars = ['a', 'c']
c --> odd_chars = ['a']
o --> odd_chars = ['a', 'o']
a --> odd_chars = ['o']
Result:
True
Upvotes: 0
Reputation: 566
Solution with JAVA
import java.util.*;
import java.lang.*;
//Classs
class Permutation {
/*
* We need to have an even number of almost all characters,
* so that half can be on one side and half can be on the other side.
* At most one character (the middle character) can have an odd count.
*/
public static boolean hasPalindrome(String str) {
boolean wasOdd = false;
for (Character c: str.toCharArray()) {
int counter = 0;
for (Character cc: str.toCharArray()) {
if (c == cc) {
counter++;
}
}
if (counter % 2 == 1) {
if (wasOdd) {
return false;
}
wasOdd = true;
}
}
return true;
}
public static void main(String args[]) throws Exception {
//Taking string input
//Scanner
Scanner s = new Scanner(System.in);
String str = s.nextLine();
if (Permutation.hasPalindrome(str)) {
System.out.println("YES"); // Writing output to STDOUT
} else {
System.out.println("NO"); // Writing output to STDOUT
}
}
}
Upvotes: 0
Reputation: 103
In order to check whether the permutation of string is palindrome or not, one can achieve it in theta(n)
using the below logic
Theoretical Explanation
Practical Code
from collections import Counter
def perm_palindrome(string_input):
count_dict = Counter(string_input)
odd_count = 0
for values in count_dict.values():
if values % 2 != 0:
odd_count += 1
if odd_count > 1:
return False
else:
return True
string_value = "aabb"
output = perm_palindrome(string_input=string_value)
print("Answer of permutation palindrome if {} is :::: {}".format(string_value, output))
Explanation of Time complexity
Counter function in the code will take theta(n)
for loop in the code can run till length of the string if all characters in the string are distinct, hence it can take maximum if theta(n)
So overall time complexity is time complexity of counter function and for loop which will be theta(n) + theta(n) = 2*theta(n)
Constant has no significance when computing the time complexity, hence overall time complexity would be theta(n)
Upvotes: 0
Reputation: 411
String palindromePermutation(String s){
Set<Character> set=new HashSet<Character>();
for(int i=0; i<s.length(); ++i){
if (!set.contains(s.charAt(i)))
set.add(s.charAt(i));
else
set.remove(s.charAt(i));
}
if(set.size() > 1){
return "NO";
}
return "YES";
}
Upvotes: 0
Reputation: 459
By java, it will take O(N)
public static int getNumberChar(char temp){
int a = Character.getNumericValue('a');
int z = Character.getNumericValue('z');
int val = Character.getNumericValue(temp);
if(val >= a && val <= z){
// System.out.println("val = " + (val - a));
return val - a;
}
return -1;
}
public static int[] frequencyForEachCharInString(String str){
int[] frequencyChar = new int[getNumberChar('z')-getNumberChar('a') +1 ];
for (char c: str.toCharArray()) {
if(getNumberChar(c) != -1){
// System.out.println("c = " + getNumberChar(c));
frequencyChar[getNumberChar(c)]++;
}
}
return frequencyChar;
}
public static boolean checkIfMaxOneOdd(int[] arr){
boolean isMaxOddOneOnly = false;
for (int index: arr) {
if(index % 2 == 1){
if(isMaxOddOneOnly){
return false;
} // that's mean i found more than one's odd in array ...
isMaxOddOneOnly =true;
}
}
return true;
}
public static boolean palindromePermutation(String str){
int[] arr = frequencyForEachCharInString(str);
return checkIfMaxOneOdd(arr);
}
Upvotes: 0
Reputation: 77847
To illustrate further "pythonic" programming, I'm "refining" pault
's answer.
def any_palindrome(myString): alpha_chars_only = [x for x in myString.lower() if x.isalpha()] counts = Counter(alpha_chars_only) number_of_odd = sum(1 for letter, cnt in counts.items() if cnt%2) return number_of_odd <= 1
Don't be so heavy-handed with the Boolean logic: just add up how many "not even" results you get directly from %
:
number_of_odd = sum(cnt%2 for cnt in counts.values())
Now, plug that directly into the comparison to return:
return sum(cnt%2 for cnt in counts.values()) <= 1
Build the Counter
directly from the input string:
counts = Counter(x for x in myString.lower() if x.isalpha())
Now, combine the two remaining lines into a direct expression:
return sum(cnt%2 for cnt in
Counter(x for x in myString.lower()
if x.isalpha()).values()) <= 1
One statement instead of four. Isn't that better?
No, it isn't ... it's hard to read. But you may want to employ these techniques from time to time as you climb up that learning curve.
Upvotes: 1
Reputation: 11
All we need to look for is a character with odd frequency, in this case, using a counter object is very useful instead of calculating the count the frequency of each character in the string we can have a counter object for the string with the frequency for every character in the string. From the values of the counter object, we can determine if more than one character with an odd frequency which makes the string not possible to be a palindrome.
from collections import Counter
def permutationPalindrome(string):
counterObject = Counter(char for char in string.lower() if char.isalpha())
no_of_odd = 0
for value in counterObject.values():
if value % 2 != 0:
no_of_odd += 1
if(no_of_odd > 1):
return False
return True
Upvotes: 0
Reputation: 91
I though of a very simple function to check if it's a permutation of a palindrome. Basically, a palindrome has to have maximum of one odd letter (the middle one). So basically the function checks if the letter in string is dividable by 2, if it's not then it's incrementing odd letter counter. Then if the odd counter is higher then 1 it's going to return False, meaning that that string cannot be a permutation of palindrome.
def is_palindrome(s):
odd_counter = 0
for letter in s:
if s.count(letter) % 2 != 0:
odd_counter += 1
if odd_counter > 1:
return False
return True
Upvotes: 0
Reputation: 1537
I think you can just do something like this:
from string import ascii_letters
from collections import Counter
s = "Mr. owl ate my Metal worm"
def is_permutation_palindrome(s):
return len([i for i in Counter(c.lower() for c in s if c in ascii_letters).values() if i&1]) < 2
print(is_permutation_palindrome(s))
You have a Counter
structure that keeps the count of the lowercase version of each letter and you simply return True if the number of letters with an odd count is 1 or less.
Here is a less compressed version of the code that should be easier to understand and doesnt use any imports:
s = "Mr. owl ate my Metal worm"
def is_permutation_palindrome(s):
counts = {}
for c in s.lower():
if c.isalpha():
if c in counts:
counts[c] += 1
else:
counts[c] = 1
odd_counts = [count for count in counts.values() if count % 2 == 1]
return len(odd_counts) < 2
Upvotes: 0
Reputation: 43504
You can certainly check all permutations, but there is a much more efficient approach.
Note that in order for a string to be a palindrome, then every letter is mirrored around the center of the string. That means a collection of letters can form a palindrome if there is at most one letter that has an odd count.
Here is how you can implement this:
The first step is to convert the string to lower case and remove the nonalpha characters (like spaces and punctuation). We can do that by using a list comprehension to iterate over each character in the string and keep only those where str.isalpha()
returns True
.
myString = "Mr. owl ate my Metal worm"
alpha_chars_only = [x for x in myString.lower() if x.isalpha()]
print(alpha_chars_only)
#['m', 'r', 'o', 'w', 'l', 'a', 't', 'e', 'm', 'y', 'm', 'e', 't', 'a', 'l', 'w', 'o', 'r', 'm']
Next count each letter. You can use collections.Counter
for this:
from collections import Counter
counts = Counter(alpha_chars_only)
print(counts)
#Counter({'m': 4, 'a': 2, 'e': 2, 'l': 2, 'o': 2, 'r': 2, 't': 2, 'w': 2, 'y': 1})
Finally count the number of letters that have an odd count. If the count is 0
or 1
, a palindrome must be possible.
number_of_odd = sum(1 for letter, cnt in counts.items() if cnt%2)
print(number_of_odd)
#1
Putting that all together, you can make a function:
def any_palindrome(myString):
alpha_chars_only = [x for x in myString.lower() if x.isalpha()]
counts = Counter(alpha_chars_only)
number_of_odd = sum(1 for letter, cnt in counts.items() if cnt%2)
return number_of_odd <= 1
print(any_palindrome(mystring))
#True
Upvotes: 6