Skip to content

Commit f4e5b3a

Browse files
committed
LeetCode 804. Unique Morse Code Words
1 parent 365e87b commit f4e5b3a

File tree

2 files changed

+180
-1
lines changed

2 files changed

+180
-1
lines changed

README.md

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -154,8 +154,9 @@ Proposed solutions to some LeetCode problems. The first column links to the prob
154154
| [745. Prefix and Suffix Search][lc745] | 🔴 Hard | [![python](res/py.png)][lc745py] |
155155
| [746. Min Cost Climbing Stairs][lc746] | 🟢 Easy | [![python](res/py.png)][lc746py] |
156156
| [792. Number of Matching Subsequences][lc792] | 🟠 Medium | [![python](res/py.png)][lc792py] |
157+
| [804. Unique Morse Code Words][lc804] | 🟢 Easy | [![python](res/py.png)][lc804py] |
157158
| [815. Bus Routes][lc815] | 🔴 Hard | [![python](res/py.png)][lc815py] |
158-
| [820. Short Encoding of Words][lc820] | 🟠 Medium | [![python](res/py.png)](leetcode/short-encoding-of-words.py) |
159+
| [820. Short Encoding of Words][lc820] | 🟠 Medium | [![python](res/py.png)][lc820py] |
159160
| [823. Binary Trees With Factors][lc823] | 🟠 Medium | [![python](res/py.png)][lc823py] |
160161
| [844. Backspace String Compare][lc844] | 🟢 Easy | [![python](res/py.png)][lc844py] |
161162
| [858. Mirror Reflection][lc858] | 🟠 Medium | [![python](res/py.png)][lc858py] |
@@ -449,9 +450,12 @@ Proposed solutions to some LeetCode problems. The first column links to the prob
449450
[lc746py]: leetcode/min-cost-climbing-stairs.py
450451
[lc792]: https://leetcode.com/problems/number-of-matching-subsequences/
451452
[lc792py]: leetcode/number-of-matching-subsequences.py
453+
[lc804]: https://leetcode.com/problems/unique-morse-code-words/
454+
[lc804py]: leetcode/unique-morse-code-words.py
452455
[lc815]: https://leetcode.com/problems/bus-routes/
453456
[lc815py]: leetcode/bus-routes.py
454457
[lc820]: https://leetcode.com/problems/short-encoding-of-words/
458+
[lc820py]: leetcode/short-encoding-of-words.py
455459
[lc823]: https://leetcode.com/problems/binary-trees-with-factors/
456460
[lc823py]: leetcode/binary-trees-with-factors.py
457461
[lc844]: https://leetcode.com/problems/backspace-string-compare/
Lines changed: 175 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,175 @@
1+
# 804. Unique Morse Code Words
2+
# 🟢 Easy
3+
#
4+
# https://leetcode.com/problems/unique-morse-code-words/
5+
#
6+
# Tags: Array - Hash Table - String
7+
8+
import timeit
9+
from string import ascii_lowercase
10+
from typing import List
11+
12+
# A hashmap mapping each letter of the alphabet to its morse representation.
13+
morse = {
14+
"a": ".-",
15+
"b": "-...",
16+
"c": "-.-.",
17+
"d": "-..",
18+
"e": ".",
19+
"f": "..-.",
20+
"g": "--.",
21+
"h": "....",
22+
"i": "..",
23+
"j": ".---",
24+
"k": "-.-",
25+
"l": ".-..",
26+
"m": "--",
27+
"n": "-.",
28+
"o": "---",
29+
"p": ".--.",
30+
"q": "--.-",
31+
"r": ".-.",
32+
"s": "...",
33+
"t": "-",
34+
"u": "..-",
35+
"v": "...-",
36+
"w": ".--",
37+
"x": "-..-",
38+
"y": "-.--",
39+
"z": "--..",
40+
}
41+
42+
# Convert all words to morse using a hashmap of letter: morse, then add
43+
# them to a set and return the length of the set.
44+
#
45+
# Time complexity: O(n) - We visit each character of the input.
46+
# Space complexity: O(n) - The set may grow to the same size as the
47+
# input array.
48+
#
49+
# Runtime: 42 ms, faster than 84.71%
50+
# Memory Usage: 13.9 MB, less than 75.48%
51+
class HashTable:
52+
def uniqueMorseRepresentations(self, words: List[str]) -> int:
53+
representations = [
54+
".-",
55+
"-...",
56+
"-.-.",
57+
"-..",
58+
".",
59+
"..-.",
60+
"--.",
61+
"....",
62+
"..",
63+
".---",
64+
"-.-",
65+
".-..",
66+
"--",
67+
"-.",
68+
"---",
69+
".--.",
70+
"--.-",
71+
".-.",
72+
"...",
73+
"-",
74+
"..-",
75+
"...-",
76+
".--",
77+
"-..-",
78+
"-.--",
79+
"--..",
80+
]
81+
mappings = dict(zip(ascii_lowercase, representations))
82+
# Define a function that converts a word to morse.
83+
def toMorse(word: str) -> str:
84+
morse = [""] * len(word)
85+
for i, c in enumerate(word):
86+
morse[i] = mappings[c]
87+
return "".join(morse)
88+
89+
# Set to store morse sequences that we have seen already.
90+
seen = set()
91+
# Iterate over all words converting them to morse and adding
92+
# them to a set of words we have seen.
93+
for word in words:
94+
seen.add(toMorse(word))
95+
# Return the number of different sequences obtained.
96+
return len(seen)
97+
98+
99+
# We can improve the solution above using the unicode point of the
100+
# character to determine the index of its conversion and set
101+
# comprehension. Theoretically this would make the code more performant
102+
# but it is not the case on the tests, maybe the call to ord() is slow.
103+
#
104+
# Time complexity: O(n) - We visit each character of the input.
105+
# Space complexity: O(n) - The set may grow to the same size as the
106+
# input array.
107+
#
108+
# Runtime: 55 ms, faster than 51.58%
109+
# Memory Usage: 13.9 MB, less than 24.27%
110+
class SetComprehension:
111+
def uniqueMorseRepresentations(self, words: List[str]) -> int:
112+
representations = [
113+
".-",
114+
"-...",
115+
"-.-.",
116+
"-..",
117+
".",
118+
"..-.",
119+
"--.",
120+
"....",
121+
"..",
122+
".---",
123+
"-.-",
124+
".-..",
125+
"--",
126+
"-.",
127+
"---",
128+
".--.",
129+
"--.-",
130+
".-.",
131+
"...",
132+
"-",
133+
"..-",
134+
"...-",
135+
".--",
136+
"-..-",
137+
"-.--",
138+
"--..",
139+
]
140+
return len(
141+
{
142+
"".join(representations[ord(c) - ord("a")] for c in word)
143+
for word in words
144+
}
145+
)
146+
147+
148+
def test():
149+
executors = [
150+
HashTable,
151+
SetComprehension,
152+
]
153+
tests = [
154+
[["gin", "zen", "gig", "msg"], 2],
155+
[["a"], 1],
156+
]
157+
for executor in executors:
158+
start = timeit.default_timer()
159+
for _ in range(1):
160+
for n, t in enumerate(tests):
161+
sol = executor()
162+
result = sol.uniqueMorseRepresentations(t[0])
163+
exp = t[1]
164+
assert result == exp, (
165+
f"\033[93m» {result} <> {exp}\033[91m for "
166+
+ f"test {n} using \033[1m{executor.__name__}"
167+
)
168+
stop = timeit.default_timer()
169+
used = str(round(stop - start, 5))
170+
cols = "{0:20}{1:10}{2:10}"
171+
res = cols.format(executor.__name__, used, "seconds")
172+
print(f"\033[92m» {res}\033[0m")
173+
174+
175+
test()

0 commit comments

Comments
 (0)