Skip to content

Commit d562109

Browse files
committed
implement more efficient solution for palindrome perm
1 parent 1be22cd commit d562109

File tree

1 file changed

+42
-7
lines changed

1 file changed

+42
-7
lines changed

Python/chapter01/1.4 - PalinPerm/miguel_1.4_sol.py

Lines changed: 42 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -7,23 +7,52 @@
77
"""
88
import unittest
99
import itertools as it
10+
import collections
11+
from typing import Callable
12+
13+
14+
def is_permutation_of_palindrome(word: str) -> bool:
15+
"""
16+
Checks if a word 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+
* all characters have an even count or all except one are even
22+
Runtime: O(n)
23+
Space Complexity: O(n)
24+
:param word: the word we check, 'word' is a possible permutation of a palindrome
25+
:return: true if word is a permutation of a palindrome, false otherwise
26+
"""
27+
char_frequencies = collections.Counter(word.lower().replace(' ', ''))
28+
num_odd_freq_chars = 0
29+
num_even_freq_chars = 0
30+
31+
for key, val in char_frequencies.items():
32+
if num_odd_freq_chars > 1:
33+
return False
34+
if val % 2 == 0:
35+
num_even_freq_chars += 1
36+
else:
37+
num_odd_freq_chars += 1
38+
return True
1039

1140

1241
def _is_palindrome(word: str) -> bool:
1342
"""
14-
Checks if word is a palindrome.
43+
Checks if word is a palindrome by checking if the forward version is the same as the backward version.
1544
A palindrome is a word or phrase that is the same forwards and backwards.
1645
Whitespace will not be considered when determining palindrome.
1746
This function is case insensitive.
18-
:param word: the word we check
47+
:param word: the word we check, possible permutation of a palindrome
1948
:return: true if word is a palindrome, false otherwise
2049
"""
2150
word_no_spaces = word.replace(' ', '').lower()
2251
reversed_word = word_no_spaces[::-1]
2352
return word_no_spaces == reversed_word
2453

2554

26-
def is_permutation_of_palindrome(word: str) -> bool:
55+
def is_permutation_of_palindrome_brute_force(word: str) -> bool:
2756
"""
2857
Given a string, this function will return whether the string is a permutation of a palindrome.
2958
A palindrome is a word or phrase that is the same forwards and backwards.
@@ -49,19 +78,23 @@ def is_permutation_of_palindrome(word: str) -> bool:
4978

5079

5180
class TestIsPermutationOfPalindromeFunction(unittest.TestCase):
52-
def test_is_permutation_of_palindrome(self):
81+
def _run_tests(self, f: Callable[[str], bool]) -> None:
5382
cases = [
5483
("Tact Coa", True),
5584
("car race", True),
5685
("ppilffli", True),
5786
("gwas", False),
58-
("sldkjflksd", False),
87+
("sldkjflks", False),
5988
(" ", True),
6089
("", True),
6190
("a", True)
6291
]
6392
for word, expected in cases:
64-
self.assertEqual(is_permutation_of_palindrome(word), expected, msg=word)
93+
self.assertEqual(f(word), expected, msg=word)
94+
95+
def test_is_permutation_of_palindrome(self):
96+
self._run_tests(is_permutation_of_palindrome_brute_force)
97+
self._run_tests(is_permutation_of_palindrome)
6598

6699
def test_is_palindrome(self):
67100
cases = [
@@ -72,7 +105,9 @@ def test_is_palindrome(self):
72105
("miguel", False),
73106
(" ", True),
74107
("", True),
75-
("a", True)
108+
("a", True),
109+
("Tacoo Cat", True),
110+
("Tacooo Cat", True)
76111
]
77112
for word, expected in cases:
78113
self.assertEqual(_is_palindrome(word), expected, msg=word)

0 commit comments

Comments
 (0)