这道题的难点在于**解密(Decrypt)**的过程。
如果直接按照题目描述的逻辑去写decrypt函数(即:把字符串切分成两个字符一组,然后尝试所有可能的组合),你会发现这是一个非常耗时的回溯过程,因为一个密文可能对应多个明文。
核心解题思路是“逆向思维” + “预处理”:
我们不需要真的去把密文还原成明文,而是反过来思考:统计字典(dictionary)中所有单词加密后的样子。
- 在初始化时,就把
dictionary里的每个单词都加密。 - 用哈希表(HashMap)记录:
加密后的字符串->出现的次数。 - 当调用
decrypt(word2)时,只需要在哈希表中查找word2出现了几次即可。这样时间复杂度降为 O(1)。
下面是完整的 Java 代码实现:
💻 Java 代码实现
importjava.util.*;classEncrypter{// 存储字符到字符串的映射 (用于加密)privateMap<Character,String>encryptMap;// 存储 "加密后的字符串" -> "在字典中出现的次数" (用于解密)privateMap<String,Integer>decryptCountMap;publicEncrypter(char[]keys,String[]values,String[]dictionary){this.encryptMap=newHashMap<>();this.decryptCountMap=newHashMap<>();// 1. 构建加密映射表for(inti=0;i<keys.length;i++){encryptMap.put(keys[i],values[i]);}// 2. 【关键步骤】预处理字典// 我们不存原始字典,而是存“字典中单词加密后”的结果及其频次for(Stringword:dictionary){StringencryptedWord=encrypt(word);// 只有当加密成功(不为空)时才统计if(encryptedWord!=null){decryptCountMap.put(encryptedWord,decryptCountMap.getOrDefault(encryptedWord,0)+1);}}}publicStringencrypt(Stringword1){StringBuildersb=newStringBuilder();for(charc:word1.toCharArray()){// 如果字符不在 keys 中,无法加密,返回空字符串if(!encryptMap.containsKey(c)){return"";}sb.append(encryptMap.get(c));}returnsb.toString();}publicintdecrypt(Stringword2){// 直接在预处理好的哈希表中查找// 如果没有找到,说明没有字典中的单词能加密成 word2,返回 0returndecryptCountMap.getOrDefault(word2,0);}}💡 关键点解析
1. 为什么这样做?
题目中的decrypt实际上是问:“这个密文word2可能是字典里的哪几个词变来的?”。
如果我们正向解密,比如密文ei可能对应a也可能对应c,组合起来可能性呈指数级增长。
通过预先计算字典中所有合法单词的加密结果,我们将复杂的“多对多”解密问题转化为了简单的“查表”问题。
2. 数据结构的选择
encryptMap(Map<Character, String>): 用来快速查找某个字符应该变成哪两个字符。decryptCountMap(Map<String, Integer>): 这是优化的核心。键是加密后的长字符串,值是该字符串在字典中对应的原词数量。
3. 边界情况处理
- 在
encrypt方法中,如果遇到keys中不存在的字符,根据题目逻辑应返回空字符串""。 - 在初始化统计字典时,也要排除掉那些包含非法字符(无法加密)的字典单词。