Skip to content

Commit 21e7165

Browse files
authored
Merge pull request #20 from miguelHx/miguel_1.4_palindrome_perm
Miguel 1.4 - Palindrome Perm [Python]
2 parents f47f006 + 595f619 commit 21e7165

File tree

1 file changed

+115
-0
lines changed

1 file changed

+115
-0
lines changed
Lines changed: 115 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,115 @@
1+
"""
2+
Python version 3.7.0
3+
1.4 - Palindrome Permutation
4+
Given a string, write a function to check if it is a permutation of a palindrome.
5+
A palindrome is a word or phrase that is the same forwards and backwards. A permutation is a
6+
rearrangement of letters. The palindrome does not need to be limited to just dictionary words.
7+
"""
8+
import unittest
9+
import itertools as it
10+
import collections
11+
from typing import Callable
12+
13+
14+
def is_permutation_of_palindrome(s: str) -> bool:
15+
"""
16+
Checks if a string is a palindrome by analyzing the frequencies of characters.
17+
A palindrome is a word or phrase that is the same forwards and backwards.
18+
When determining character frequencies, word will be put to lowercase
19+
and spaces will not be counted
20+
A palindrome also has the following property:
21+
* at most one character appears an odd number of times
22+
Runtime: O(n)
23+
Space Complexity: O(n)
24+
:param s: the string we check, 's' is a possible permutation of a palindrome
25+
:return: true if s is a permutation of a palindrome, false otherwise
26+
"""
27+
char_frequencies = collections.Counter(s.lower().replace(' ', ''))
28+
num_odd_freq_chars = 0
29+
30+
for key, val in char_frequencies.items():
31+
if val % 2 == 0:
32+
continue
33+
num_odd_freq_chars += 1
34+
if num_odd_freq_chars > 1:
35+
return False
36+
return True
37+
38+
39+
def _is_palindrome(s: str) -> bool:
40+
"""
41+
Checks if s is a palindrome by checking if the forward version is the same as the backward version.
42+
A palindrome is a word or phrase that is the same forwards and backwards.
43+
Whitespace will not be considered when determining palindrome.
44+
This function is case insensitive.
45+
Runtime: O(n)
46+
Space Complexity: O(n)
47+
:param s: the string we check, possible permutation of a palindrome
48+
:return: true if s is a palindrome, false otherwise
49+
"""
50+
s_no_spaces = s.replace(' ', '').lower()
51+
reversed_s = s_no_spaces[::-1]
52+
return s_no_spaces == reversed_s
53+
54+
55+
def is_permutation_of_palindrome_brute_force(s: str) -> bool:
56+
"""
57+
Given a string, this function will return whether the string is a permutation of a palindrome.
58+
A palindrome is a word or phrase that is the same forwards and backwards.
59+
A permutation is a rearrangement of letters.
60+
When evaluating whether a string is the same forwards and backwards, we will
61+
omit whitespace. For ex: "taco cat" would not equal "tac ocat" IF we expect a space at the 4th index for
62+
the reversed version. So, the space will not be taken into account only when determining palindrome.
63+
Assuming ASCII
64+
Runtime is O(n!)
65+
Space complexity is O(n)
66+
Given: Expect:
67+
Tact Coa True (permutations: "taco cat", "atco cta")
68+
:param s: the string that we want to check for perm of a palindrome
69+
:return: True if s is a palindrome, False otherwise.
70+
"""
71+
s_no_spaces = s.replace(' ', '')
72+
for p in it.permutations(s_no_spaces):
73+
if _is_palindrome(''.join(p)):
74+
return True
75+
return False
76+
77+
78+
class TestIsPermutationOfPalindromeFunction(unittest.TestCase):
79+
def _run_tests(self, f: Callable[[str], bool]) -> None:
80+
cases = [
81+
("Tact Coa", True),
82+
("car race", True),
83+
("ppilffli", True),
84+
("gwas", False),
85+
("sldkjflks", False),
86+
(" ", True),
87+
("", True),
88+
("a", True)
89+
]
90+
for s, expected in cases:
91+
self.assertEqual(f(s), expected, msg=s)
92+
93+
def test_is_permutation_of_palindrome(self):
94+
self._run_tests(is_permutation_of_palindrome_brute_force)
95+
self._run_tests(is_permutation_of_palindrome)
96+
97+
def test_is_palindrome(self):
98+
cases = [
99+
("Taco Cat", True),
100+
("race car", True),
101+
("flippilf", True),
102+
("swag", False),
103+
("miguel", False),
104+
(" ", True),
105+
("", True),
106+
("a", True),
107+
("Tacoo Cat", True),
108+
("Tacooo Cat", True)
109+
]
110+
for s, expected in cases:
111+
self.assertEqual(_is_palindrome(s), expected, msg=s)
112+
113+
114+
if __name__ == '__main__':
115+
unittest.main()

0 commit comments

Comments
 (0)