{x}
blog image

Decode the Message

You are given the strings key and message, which represent a cipher key and a secret message, respectively. The steps to decode message are as follows:

  1. Use the first appearance of all 26 lowercase English letters in key as the order of the substitution table.
  2. Align the substitution table with the regular English alphabet.
  3. Each letter in message is then substituted using the table.
  4. Spaces ' ' are transformed to themselves.
  • For example, given key = "happy boy" (actual key would have at least one instance of each letter in the alphabet), we have the partial substitution table of ('h' -> 'a', 'a' -> 'b', 'p' -> 'c', 'y' -> 'd', 'b' -> 'e', 'o' -> 'f').

Return the decoded message.

 

Example 1:

Input: key = "the quick brown fox jumps over the lazy dog", message = "vkbs bs t suepuv"
Output: "this is a secret"
Explanation: The diagram above shows the substitution table.
It is obtained by taking the first appearance of each letter in "the quick brown fox jumps over the lazy dog".

Example 2:

Input: key = "eljuxhpwnyrdgtqkviszcfmabo", message = "zwx hnfx lqantp mnoeius ycgk vcnjrdb"
Output: "the five boxing wizards jump quickly"
Explanation: The diagram above shows the substitution table.
It is obtained by taking the first appearance of each letter in "eljuxhpwnyrdgtqkviszcfmabo".

 

Constraints:

  • 26 <= key.length <= 2000
  • key consists of lowercase English letters and ' '.
  • key contains every letter in the English alphabet ('a' to 'z') at least once.
  • 1 <= message.length <= 2000
  • message consists of lowercase English letters and ' '.

Solution Explanation

This problem involves decoding a message using a cipher key. The key determines a substitution table where the first occurrence of each letter in the key maps to the next available letter in the alphabet (a-z). The solution involves creating this mapping and then applying it to the message.

Approach:

  1. Create the substitution table: We iterate through the key string. For each character, if it's not already in our mapping and it's a lowercase alphabet character, we map it to the next unused alphabet character. We use a hash map (dictionary in Python) or an array to efficiently store this mapping. Spaces are handled specially, remaining as spaces.

  2. Decode the message: We iterate through the message string. For each character, we look it up in our substitution table. If found, we replace it with its corresponding decoded character. If not found (it should be a space), the character remains unchanged.

  3. Return the decoded message: Finally, we concatenate the decoded characters to form the decoded message string.

Code Explanation with Complexity Analysis

The code examples below demonstrate the approach in multiple programming languages. The time complexity is dominated by the iterations through the key and message strings. The space complexity depends on the size of the substitution table, which is constant (O(1) because it's limited to 26 letters).

Time Complexity: O(M + K), where M is the length of the message and K is the length of the key. We iterate through the key once to create the mapping and the message once to decode.

Space Complexity: O(1). The space used by the substitution table is constant (26 letters), regardless of the input size.

Python:

class Solution:
    def decodeMessage(self, key: str, message: str) -> str:
        mapping = {} #Using a dictionary for efficient lookup.
        alphabet_index = 0
        for char in key:
            if char != ' ' and char not in mapping:
                mapping[char] = chr(ord('a') + alphabet_index) #chr converts ascii to character, ord does the opposite
                alphabet_index += 1
        mapping[' '] = ' ' #Handle spaces separately.
 
        decoded_message = ""
        for char in message:
            decoded_message += mapping[char] #Efficient lookup in dictionary
 
        return decoded_message
 

Java:

class Solution {
    public String decodeMessage(String key, String message) {
        char[] mapping = new char[26]; // Array for efficient lookup (index represents a-z)
        Arrays.fill(mapping, ' '); //Initialize with spaces.
        int index = 0;
        for (char c : key.toCharArray()) {
            if (c != ' ' && mapping[c - 'a'] == ' ') {
                mapping[c - 'a'] = (char) ('a' + index++);
            }
        }
        StringBuilder decodedMessage = new StringBuilder();
        for (char c : message.toCharArray()) {
            decodedMessage.append(c == ' ' ? ' ' : mapping[c - 'a']);
        }
        return decodedMessage.toString();
    }
}

C++:

class Solution {
public:
    string decodeMessage(string key, string message) {
        vector<char> mapping(26, ' '); // Vector for efficient lookup.
        int index = 0;
        for (char c : key) {
            if (c != ' ' && mapping[c - 'a'] == ' ') {
                mapping[c - 'a'] = 'a' + index++;
            }
        }
        string decodedMessage = "";
        for (char c : message) {
            decodedMessage += (c == ' ' ? ' ' : mapping[c - 'a']);
        }
        return decodedMessage;
    }
};

The other languages (Go, TypeScript, Rust, C) follow a similar structure, adapting the data structures and syntax as needed while maintaining the same overall algorithmic approach and complexity. The core idea is always to create a fast lookup table (hash map or array) for character substitution and efficiently apply it to the message string.