class Encrypter:
def __init__(self, keys, values, dictionary):
self.char_to_code = {k: v for k, v in zip(keys, values)}
self.code_to_chars = {}
for k, v in zip(keys, values):
self.code_to_chars.setdefault(v, []).append(k)
self.dictionary = set(dictionary)
self.encrypted_count = {}
for word in dictionary:
enc = self.encrypt(word)
self.encrypted_count[enc] = self.encrypted_count.get(enc, 0) + 1
def encrypt(self, word1: str) -> str:
res = []
for c in word1:
if c not in self.char_to_code:
return ""
res.append(self.char_to_code[c])
return ''.join(res)
def decrypt(self, word2: str) -> int:
return self.encrypted_count.get(word2, 0)
class Encrypter {
public:
unordered_map<char, string> charToCode;
unordered_map<string, vector<char>> codeToChars;
unordered_map<string, int> encryptedCount;
Encrypter(vector<char>& keys, vector<string>& values, vector<string>& dictionary) {
for (int i = 0; i < keys.size(); ++i) {
charToCode[keys[i]] = values[i];
codeToChars[values[i]].push_back(keys[i]);
}
for (auto& word : dictionary) {
string enc = encrypt(word);
encryptedCount[enc]++;
}
}
string encrypt(string word1) {
string res = "";
for (char c : word1) {
if (!charToCode.count(c)) return "";
res += charToCode[c];
}
return res;
}
int decrypt(string word2) {
return encryptedCount.count(word2) ? encryptedCount[word2] : 0;
}
};
class Encrypter {
private Map<Character, String> charToCode = new HashMap<>();
private Map<String, List<Character>> codeToChars = new HashMap<>();
private Map<String, Integer> encryptedCount = new HashMap<>();
public Encrypter(char[] keys, String[] values, String[] dictionary) {
for (int i = 0; i < keys.length; i++) {
charToCode.put(keys[i], values[i]);
codeToChars.computeIfAbsent(values[i], k -> new ArrayList<>()).add(keys[i]);
}
for (String word : dictionary) {
String enc = encrypt(word);
encryptedCount.put(enc, encryptedCount.getOrDefault(enc, 0) + 1);
}
}
public String encrypt(String word1) {
StringBuilder sb = new StringBuilder();
for (char c : word1.toCharArray()) {
if (!charToCode.containsKey(c)) return "";
sb.append(charToCode.get(c));
}
return sb.toString();
}
public int decrypt(String word2) {
return encryptedCount.getOrDefault(word2, 0);
}
}
class Encrypter {
constructor(keys, values, dictionary) {
this.charToCode = {};
this.codeToChars = {};
for (let i = 0; i < keys.length; ++i) {
this.charToCode[keys[i]] = values[i];
if (!this.codeToChars[values[i]]) this.codeToChars[values[i]] = [];
this.codeToChars[values[i]].push(keys[i]);
}
this.encryptedCount = {};
for (let word of dictionary) {
let enc = this.encrypt(word);
this.encryptedCount[enc] = (this.encryptedCount[enc] || 0) + 1;
}
}
encrypt(word1) {
let res = [];
for (let c of word1) {
if (!(c in this.charToCode)) return "";
res.push(this.charToCode[c]);
}
return res.join('');
}
decrypt(word2) {
return this.encryptedCount[word2] || 0;
}
}
You are given three inputs:
keys
: An array of characters representing the possible original letters.values
: An array of strings, where values[i]
is the code for keys[i]
.dictionary
: An array of valid words, all of which can be encrypted using the provided keys and values.Encrypter
with the following methods:
encrypt(word1)
: Encrypts a string word1
by replacing each character with its corresponding code (from keys
and values
), concatenating the codes.decrypt(word2)
: Returns the number of words in dictionary
that, when encrypted, equal word2
.word1
must be present in keys
to be encrypted; otherwise, return an empty string.
The problem requires us to create a two-way mapping: from character to code (for encryption), and from code to possible characters (for decryption).
For encrypt
, the mapping is straightforward: look up each character and append its code.
For decrypt
, the brute-force way would be to generate all possible words that could map to the encrypted string, but this is inefficient. Instead, since we have a finite dictionary, we can precompute the encrypted version of every word in the dictionary and simply count the matches.
This approach shifts from brute-force generation to efficient lookup, leveraging the constraints that all valid words are from the given dictionary.
We design the Encrypter
class as follows:
decrypt
queries in O(1) time using a hash map.Suppose:
keys = ['a', 'b', 'c', 'd']
values = ['ei', 'zf', 'ei', 'am']
dictionary = ['abcd', 'acbd', 'adbc', 'badc', 'dacb', 'cadb', 'cbda', 'abad']
Brute-force Approach:
The key insight is to avoid brute-force word generation by leveraging the finite dictionary and precomputing all possible encrypted forms. Efficient hash map lookups make both encryption and decryption fast. The solution is elegant because it turns an apparently complex decryption task into a simple counting problem by smart use of preprocessing and data structures.