LeetCode Problem Workspace

Encrypt and Decrypt Strings

The 'Encrypt and Decrypt Strings' problem involves creating a data structure that can encrypt and decrypt strings using mappings.

category

5

Topics

code_blocks

5

Code langs

hub

3

Related

Practice Focus

Hard · Array scanning plus hash lookup

bolt

Answer-first summary

The 'Encrypt and Decrypt Strings' problem involves creating a data structure that can encrypt and decrypt strings using mappings.

Interview AiBox logo

Ace coding interviews with Interview AiBox guidance for Array scanning plus hash lookup

Try AiBox Copilotarrow_forward

To solve this problem, you need to create a class that supports both encryption and decryption operations. Encryption maps each character of a string to a corresponding value, while decryption matches the encrypted string to all possible original strings. Using arrays and hashmaps is essential for optimizing these operations.

Problem Statement

You are given an array 'keys' of unique characters and an array 'values' of strings, each with a length of 2. You are also given a 'dictionary' array containing all valid decrypted strings. The goal is to implement a data structure that supports both encryption and decryption of a string based on the mappings in 'keys' and 'values'.

For encryption, you map each character in the string to its corresponding pair of characters from 'values'. If a character is not found in 'keys', return an empty string. For decryption, the process is reversed, mapping encrypted segments back to possible original characters and checking how many of the resulting strings appear in the 'dictionary'.

Examples

Example 1

Input: See original problem statement.

Output: See original problem statement.

Input ["Encrypter", "encrypt", "decrypt"] [[['a', 'b', 'c', 'd'], ["ei", "zf", "ei", "am"], ["abcd", "acbd", "adbc", "badc", "dacb", "cadb", "cbda", "abad"]], ["abcd"], ["eizfeiam"]] Output [null, "eizfeiam", 2]

Explanation Encrypter encrypter = new Encrypter([['a', 'b', 'c', 'd'], ["ei", "zf", "ei", "am"], ["abcd", "acbd", "adbc", "badc", "dacb", "cadb", "cbda", "abad"]); encrypter.encrypt("abcd"); // return "eizfeiam". // 'a' maps to "ei", 'b' maps to "zf", 'c' maps to "ei", and 'd' maps to "am". encrypter.decrypt("eizfeiam"); // return 2. // "ei" can map to 'a' or 'c', "zf" maps to 'b', and "am" maps to 'd'. // Thus, the possible strings after decryption are "abad", "cbad", "abcd", and "cbcd". // 2 of those strings, "abad" and "abcd", appear in dictionary, so the answer is 2.

Constraints

  • 1 <= keys.length == values.length <= 26
  • values[i].length == 2
  • 1 <= dictionary.length <= 100
  • 1 <= dictionary[i].length <= 100
  • All keys[i] and dictionary[i] are unique.
  • 1 <= word1.length <= 2000
  • 2 <= word2.length <= 200
  • All word1[i] appear in keys.
  • word2.length is even.
  • keys, values[i], dictionary[i], word1, and word2 only contain lowercase English letters.
  • At most 200 calls will be made to encrypt and decrypt in total.

Solution Approach

Encryption via Hashmap

For the encryption process, create a hashmap where each key-value pair corresponds to a character from 'keys' and its encrypted value from 'values'. Use this hashmap to convert each character in the input string to its corresponding encrypted value.

Decryption by Checking Valid Matches

For decryption, split the encrypted string into segments of length 2 (since each value is of length 2). For each segment, find all possible original characters from 'keys' that could map to the segment. After forming possible decrypted strings, check how many are valid according to the 'dictionary'.

Efficient Data Structures for Fast Lookups

To improve efficiency, use a hash table to store the possible decrypted strings from 'keys' and 'values'. This will allow you to quickly lookup and match the segments during decryption, thus reducing computation time for larger input sizes.

Complexity Analysis

Metric Value
Time Depends on the final approach
Space Depends on the final approach

The time complexity depends on the number of characters in the string and the size of the dictionary. Both encryption and decryption can be done in linear time relative to the length of the input strings, assuming hashmaps and other efficient lookups are used. Space complexity is influenced by the size of the 'keys', 'values', and 'dictionary'.

What Interviewers Usually Probe

  • Assess the candidate's ability to handle encryption and decryption using hashmaps.
  • Test if the candidate understands the importance of efficient lookups for decryption and encryption.
  • Evaluate how well the candidate can manage complex string manipulations and check for dictionary matches.

Common Pitfalls or Variants

Common pitfalls

  • Failing to handle cases where a character in the string doesn't exist in the 'keys' array, returning an empty string.
  • Inefficient decryption algorithms that fail to quickly find valid strings in the 'dictionary'.
  • Not properly handling the case where a string has multiple possible decrypted matches.

Follow-up variants

  • Increasing the length of the 'values' array beyond 2 characters, which requires adjustments to the segment length for decryption.
  • Handling encrypted strings that are extremely large or require optimizations in the lookup process.
  • Adding multiple dictionaries and handling scenarios with several potential valid decrypted strings for a single encrypted input.

FAQ

What is the primary approach to solving the 'Encrypt and Decrypt Strings' problem?

The primary approach involves using a hashmap to map characters to encrypted values for encryption and reversing the process for decryption while checking dictionary validity.

How can I efficiently decrypt strings in the 'Encrypt and Decrypt Strings' problem?

Efficient decryption involves splitting the encrypted string into segments of length 2, finding potential matches for each segment, and counting how many resulting strings are valid according to the dictionary.

What is the role of hashmaps in this problem?

Hashmaps are used to quickly map characters to their encrypted values during encryption and to check valid decryption possibilities during decryption.

How do I handle cases where a character isn't found in the 'keys' array?

If a character is not found in the 'keys' array, the encryption process should return an empty string as it cannot be encrypted.

What happens if multiple strings match during decryption?

When multiple possible decrypted strings match, the goal is to count how many of them appear in the 'dictionary'.

terminal

Solution

Solution 1: Hash Table

We use a hash table $\textit{mp}$ to record the encryption result of each character, and another hash table $\textit{cnt}$ to record the number of occurrences of each encryption result.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
class Encrypter:
    def __init__(self, keys: List[str], values: List[str], dictionary: List[str]):
        self.mp = dict(zip(keys, values))
        self.cnt = Counter(self.encrypt(v) for v in dictionary)

    def encrypt(self, word1: str) -> str:
        res = []
        for c in word1:
            if c not in self.mp:
                return ''
            res.append(self.mp[c])
        return ''.join(res)

    def decrypt(self, word2: str) -> int:
        return self.cnt[word2]


# Your Encrypter object will be instantiated and called as such:
# obj = Encrypter(keys, values, dictionary)
# param_1 = obj.encrypt(word1)
# param_2 = obj.decrypt(word2)
Encrypt and Decrypt Strings Solution: Array scanning plus hash lookup | LeetCode #2227 Hard