Facebook Pixel

804. Unique Morse Code Words

EasyArrayHash TableString
Leetcode Link

Problem Description

You are given a mapping of each letter in the English alphabet (a-z) to its corresponding Morse code representation. The Morse code uses dots (.) and dashes (-) to encode each letter.

The mapping is provided as:

  • 'a' → ".-"
  • 'b' → "-..."
  • 'c' → "-.-."
  • And so on for all 26 letters

Given an array of strings words, you need to:

  1. Convert each word to its Morse code representation by:

    • Taking each letter in the word
    • Looking up its Morse code equivalent
    • Concatenating all the Morse codes together (without spaces)
  2. Count how many unique Morse code representations exist among all the transformed words.

For example:

  • The word "cab" becomes "-.-..--..." because:
    • 'c' → "-.-."
    • 'a' → ".-"
    • 'b' → "-..."
    • Concatenated: "-.-." + ".-" + "-..." = "-.-..--..."

The solution works by:

  1. Creating a list codes containing the Morse code for each letter in alphabetical order
  2. For each word, transforming it to Morse code by:
    • Converting each character to its position in the alphabet using ord(c) - ord('a')
    • Using that position to look up the corresponding Morse code
    • Joining all the Morse codes together
  3. Using a set comprehension to automatically eliminate duplicate transformations
  4. Returning the size of the set, which represents the count of unique Morse code representations
Quick Interview Experience
Help others by sharing your interview experience
Have you seen this problem before?

Intuition

The key insight is that we need to count unique patterns, not unique words. Multiple different words might produce the same Morse code pattern, and we only want to count each pattern once.

Think about it this way: if we have words like "ab" and "d", they might produce different or identical Morse code patterns. We don't care about the original words anymore - we only care about how many distinct patterns we can create.

The natural approach is to:

  1. Transform each word into its Morse code representation
  2. Keep track of all the unique transformations we've seen

Since we're looking for unique values, a set is the perfect data structure. Sets automatically handle duplicates for us - if we try to add the same Morse code pattern twice, the set will only keep one copy.

The transformation itself is straightforward: for each letter in a word, we need to find its corresponding Morse code. Since the letters 'a' through 'z' map to indices 0 through 25, we can store the Morse codes in an array and use ord(c) - ord('a') to convert any lowercase letter to its index position.

For example, if we have the words ["gin", "zen", "gig", "msg"]:

  • "gin" → "--...-.."
  • "zen" → "--...-.."
  • "gig" → "--...--."
  • "msg" → "--...--."

Notice that "gin" and "zen" produce the same pattern, as do "gig" and "msg". So even though we have 4 words, we only have 2 unique Morse code representations.

By using a set to store all transformations and then returning its length, we elegantly solve the problem in one pass through the input.

Solution Approach

The implementation uses a set comprehension to efficiently transform and count unique Morse code representations.

Step 1: Define the Morse Code Mapping

First, we create an array codes where each index corresponds to a letter's position in the alphabet:

codes = [".-", "-...", "-.-.", "-..", ".", "...-", ...]
  • Index 0 contains the Morse code for 'a'
  • Index 1 contains the Morse code for 'b'
  • And so on through index 25 for 'z'

Step 2: Transform Each Word Using Set Comprehension

The core logic is implemented in a single set comprehension:

s = {''.join([codes[ord(c) - ord('a')] for c in word]) for word in words}

Let's break this down from inside out:

  1. Character to Index Conversion: ord(c) - ord('a')

    • For each character c in a word, calculate its alphabetical position
    • ord('a') - ord('a') = 0, ord('b') - ord('a') = 1, etc.
  2. Morse Code Lookup: codes[ord(c) - ord('a')]

    • Use the calculated index to fetch the corresponding Morse code from the array
  3. Word Transformation: [codes[ord(c) - ord('a')] for c in word]

    • Create a list of Morse codes for all characters in the word
    • For "cab": ['-.-.', '.-', '-...']
  4. Concatenation: ''.join(...)

    • Join all Morse codes without any separator
    • ['-.-.', '.-', '-...'] becomes '-.-..--...'
  5. Set Construction: {... for word in words}

    • Process all words and store results in a set
    • Duplicates are automatically eliminated

Step 3: Return the Count

return len(s)

The length of the set gives us the number of unique Morse code transformations.

Time Complexity: O(n * m) where n is the number of words and m is the average length of each word.

Space Complexity: O(n * m) for storing the unique transformations in the set.

Ready to land your dream job?

Unlock your dream job with a 5-minute evaluator for a personalized learning plan!

Start Evaluator

Example Walkthrough

Let's walk through a small example with the words ["a", "b", "z", "a"].

Step 1: Set up the Morse code mapping

codes = [".-", "-...", "-.-.", "-..", ".", "..-.", "--.", "....", "..", ".---", "-.-", ".-..", "--", "-.", "---", ".--.", "--.-", ".-.", "...", "-", "..-", "...-", ".--", "-..-", "-.--", "--.."]

Step 2: Transform each word to Morse code

For word "a":

  • Character 'a': ord('a') - ord('a') = 0
  • Look up codes[0] = ".-"
  • Morse representation: ".-"

For word "b":

  • Character 'b': ord('b') - ord('a') = 1
  • Look up codes[1] = "-..."
  • Morse representation: "-..."

For word "z":

  • Character 'z': ord('z') - ord('a') = 25
  • Look up codes[25] = "--.."
  • Morse representation: "--.."

For word "a" (second occurrence):

  • Character 'a': ord('a') - ord('a') = 0
  • Look up codes[0] = ".-"
  • Morse representation: ".-"

Step 3: Collect unique transformations in a set

  • Processing all words: {".-", "-...", "--..", ".-"}
  • Since sets only keep unique values: {".-", "-...", "--.."}

Step 4: Count unique transformations

  • len({".-", "-...", "--.."}) = 3

Even though we had 4 words, only 3 unique Morse code patterns exist because "a" appeared twice.

Let's try another example with ["gin", "zen"]:

For "gin":

  • 'g': ord('g') - ord('a') = 6codes[6] = "--."
  • 'i': ord('i') - ord('a') = 8codes[8] = ".."
  • 'n': ord('n') - ord('a') = 13codes[13] = "-."
  • Concatenate: "--." + ".." + "-." = "--...-.."

For "zen":

  • 'z': ord('z') - ord('a') = 25codes[25] = "--.."
  • 'e': ord('e') - ord('a') = 4codes[4] = "."
  • 'n': ord('n') - ord('a') = 13codes[13] = "-."
  • Concatenate: "--.." + "." + "-." = "--...-.."

Both words produce "--...-..", so the set contains only one unique pattern: {"--...-.."} Result: len({"--...-.."}) = 1

Solution Implementation

1class Solution:
2    def uniqueMorseRepresentations(self, words: List[str]) -> int:
3        # Morse code mappings for letters a-z
4        morse_codes = [
5            ".-",    # a
6            "-...",  # b
7            "-.-.",  # c
8            "-..",   # d
9            ".",     # e
10            "..-.",  # f
11            "--.",   # g
12            "....",  # h
13            "..",    # i
14            ".---",  # j
15            "-.-",   # k
16            ".-..",  # l
17            "--",    # m
18            "-.",    # n
19            "---",   # o
20            ".--.",  # p
21            "--.-",  # q
22            ".-.",   # r
23            "...",   # s
24            "-",     # t
25            "..-",   # u
26            "...-",  # v
27            ".--",   # w
28            "-..-",  # x
29            "-.--",  # y
30            "--..",  # z
31        ]
32      
33        # Create a set to store unique morse code transformations
34        # For each word, convert each character to its morse code equivalent
35        # and concatenate them to form the complete morse representation
36        unique_transformations = {
37            ''.join([morse_codes[ord(char) - ord('a')] for char in word]) 
38            for word in words
39        }
40      
41        # Return the count of unique morse code representations
42        return len(unique_transformations)
43
1class Solution {
2    public int uniqueMorseRepresentations(String[] words) {
3        // Morse code mapping for each letter a-z
4        String[] morseCodeTable = new String[] {
5            ".-", "-...", "-.-.", "-..", ".", "..-.", "--.", "....",
6            "..", ".---", "-.-", ".-..", "--", "-.", "---", ".--.", 
7            "--.-", ".-.", "...", "-", "..-", "...-", ".--", "-..-", 
8            "-.--", "--.."
9        };
10      
11        // Set to store unique morse code transformations
12        Set<String> uniqueTransformations = new HashSet<>();
13      
14        // Process each word in the input array
15        for (String word : words) {
16            // Build morse code representation for current word
17            StringBuilder morseCode = new StringBuilder();
18          
19            // Convert each character to its morse code equivalent
20            for (char character : word.toCharArray()) {
21                // Map character to morse code using index (character - 'a' gives 0-25)
22                morseCode.append(morseCodeTable[character - 'a']);
23            }
24          
25            // Add the complete morse code transformation to the set
26            uniqueTransformations.add(morseCode.toString());
27        }
28      
29        // Return the count of unique morse code transformations
30        return uniqueTransformations.size();
31    }
32}
33
1class Solution {
2public:
3    int uniqueMorseRepresentations(vector<string>& words) {
4        // Morse code representations for each letter from 'a' to 'z'
5        vector<string> morseCodeTable = {
6            ".-",    "-...",  "-.-.",  "-..",   ".",     "..-.",  "--.",   
7            "....",  "..",    ".---",  "-.-",   ".-..",  "--",    "-.",
8            "---",   ".--.",  "--.-",  ".-.",   "...",   "-",     "..-",   
9            "...-",  ".--",   "-..-",  "-.--",  "--.."
10        };
11      
12        // Set to store unique morse code transformations
13        unordered_set<string> uniqueTransformations;
14      
15        // Process each word in the input array
16        for (const auto& word : words) {
17            string morseTransformation;
18          
19            // Convert each character in the word to its morse code representation
20            for (const char& character : word) {
21                // Map character to morse code using index (character - 'a')
22                morseTransformation += morseCodeTable[character - 'a'];
23            }
24          
25            // Add the complete morse transformation to the set
26            uniqueTransformations.insert(morseTransformation);
27        }
28      
29        // Return the count of unique morse code transformations
30        return uniqueTransformations.size();
31    }
32};
33
1// Morse code representations for each letter a-z
2const MORSE_CODES: string[] = [
3    '.-',    // a
4    '-...',  // b
5    '-.-.',  // c
6    '-..',   // d
7    '.',     // e
8    '..-.',  // f
9    '--.',   // g
10    '....',  // h
11    '..',    // i
12    '.---',  // j
13    '-.-',   // k
14    '.-..',  // l
15    '--',    // m
16    '-.',    // n
17    '---',   // o
18    '.--.',  // p
19    '--.-',  // q
20    '.-.',   // r
21    '...',   // s
22    '-',     // t
23    '..-',   // u
24    '...-',  // v
25    '.--',   // w
26    '-..-',  // x
27    '-.--',  // y
28    '--..',  // z
29];
30
31/**
32 * Counts the number of unique Morse code representations among the given words
33 * @param words - Array of lowercase English words to convert to Morse code
34 * @returns The number of unique Morse code transformations
35 */
36function uniqueMorseRepresentations(words: string[]): number {
37    // Transform each word to its Morse code representation
38    const morseTransformations: string[] = words.map((word: string) => {
39        // Convert each character in the word to its Morse code equivalent
40        return word
41            .split('')
42            .map((char: string) => {
43                // Calculate the index by subtracting ASCII value of 'a' from current character
44                const index: number = char.charCodeAt(0) - 'a'.charCodeAt(0);
45                return MORSE_CODES[index];
46            })
47            .join(''); // Concatenate all Morse codes for the word
48    });
49  
50    // Use Set to filter unique transformations and return the count
51    const uniqueTransformations: Set<string> = new Set(morseTransformations);
52    return uniqueTransformations.size;
53}
54

Time and Space Complexity

Time Complexity: O(n * m)

  • n is the number of words in the input list
  • m is the average length of each word
  • For each word, we iterate through each character to build the Morse code representation
  • The ord(c) - ord('a') operation is O(1) for each character
  • String concatenation using ''.join() takes O(m) time for each word
  • Set insertion is O(1) on average for each transformed word
  • Overall: O(n * m) for processing all words

Space Complexity: O(n * m)

  • The codes array is a constant with 26 elements: O(1)
  • The set s can contain at most n unique Morse code representations
  • Each Morse code representation has length proportional to the word length m
  • In the worst case where all words produce unique Morse codes, we store n strings of average length m
  • The list comprehension creates temporary strings for each word before adding to the set
  • Overall: O(n * m) for storing the Morse code representations

Learn more about how to find time and space complexity quickly.

Common Pitfalls

1. Incorrect Character-to-Index Mapping

A common mistake is using the wrong formula to convert characters to array indices, such as:

  • Using ord(c) - 'a' instead of ord(c) - ord('a') (mixing character and integer)
  • Using ord(c) - ord('A') for lowercase letters (wrong ASCII offset)
  • Forgetting to subtract ord('a') entirely and just using ord(c)

Example of incorrect code:

# Wrong: This will cause an IndexError
morse_representation = ''.join([morse_codes[ord(char)] for char in word])

# Wrong: This will cause a TypeError
morse_representation = ''.join([morse_codes[ord(char) - 'a'] for char in word])

Solution: Always use ord(char) - ord('a') to get the correct 0-based index for lowercase letters.

2. Using a List Instead of a Set

Some might accidentally use a list to store transformations and then try to count unique elements:

# Inefficient approach
transformations = []
for word in words:
    morse = ''.join([morse_codes[ord(c) - ord('a')] for c in word])
    if morse not in transformations:
        transformations.append(morse)
return len(transformations)

Solution: Use a set from the beginning to automatically handle duplicates and improve performance from O(n²) to O(n).

3. Adding Separators Between Morse Codes

Adding spaces or other separators between individual letter codes changes the problem:

# Wrong: adds spaces between morse codes
morse_representation = ' '.join([morse_codes[ord(c) - ord('a')] for c in word])

Solution: Use ''.join() with an empty string to concatenate without separators.

4. Handling Non-Lowercase or Non-Alphabetic Characters

If the input contains uppercase letters or non-alphabetic characters without proper validation:

# This will fail if word contains uppercase or special characters
morse = ''.join([morse_codes[ord(c) - ord('a')] for c in word])

Solution: Either validate input or normalize it:

# Convert to lowercase first if needed
morse = ''.join([morse_codes[ord(c.lower()) - ord('a')] for c in word if c.isalpha()])

5. Morse Code Array Index Mismatch

Ensuring the morse code array has exactly 26 elements in the correct order. Missing or misaligned codes will produce wrong results:

# Wrong: Missing some letters or wrong order
morse_codes = [".-", "-...", ".", "-..", "-.-.", ...]  # Wrong order

Solution: Double-check that the array has all 26 morse codes in alphabetical order from 'a' to 'z'.

Discover Your Strengths and Weaknesses: Take Our 5-Minute Quiz to Tailor Your Study Plan:

What is the best way of checking if an element exists in an unsorted array once in terms of time complexity? Select the best that applies.


Recommended Readings

Want a Structured Path to Master System Design Too? Don’t Miss This!

Load More