Java暴力解密项目:指定字母表固定长度全组合密钥生成方法实现问题
如何高效生成指定长度的字母表组合(Java实现)
嘿,我完全懂你的需求——不想先生成所有长度的组合再筛选,而是直接精准生成指定长度的密钥,这确实是更优的方案,能避免不必要的内存浪费和计算开销,尤其是当字母表规模大、密钥长度不短的时候。
核心思路:直接构建指定长度的组合
我们的目标是生成恰好为keyLength长度的所有字母表字符组合,不需要生成短于该长度的中间结果。这里有两种实用的实现方式:递归法(代码简洁易理解)和迭代法(避免递归栈溢出,适合更长的密钥)。
方法一:递归实现
递归的逻辑很直观:从空字符串开始,每次给当前字符串拼接字母表中的一个字符,直到字符串长度达到keyLength时,将其加入结果列表。
import java.util.ArrayList; import java.util.List; public class BruteForceDecrypter { private final String alphabet; public BruteForceDecrypter(String alphabet) { this.alphabet = alphabet; } // 对外暴露的方法:获取指定长度的所有可能密钥 public List<String> getPossibleKeys(int keyLength) { List<String> keys = new ArrayList<>(); generateKeysRecursively("", keyLength, keys); return keys; } // 递归辅助方法:生成密钥 private void generateKeysRecursively(String currentKey, int remainingLength, List<String> keys) { // 基准条件:剩余长度为0,说明当前密钥已达标 if (remainingLength == 0) { keys.add(currentKey); return; } // 遍历字母表每个字符,拼接后继续递归 for (char c : alphabet.toCharArray()) { generateKeysRecursively(currentKey + c, remainingLength - 1, keys); } } // 你的decrypt方法可以直接复用这个getPossibleKeys public void decrypt(int keyLength, String encryptedText) { List<String> keysArray = getPossibleKeys(keyLength); for (String key : keysArray) { System.out.print(doDecryption(encryptedText, key)); } } // 假设你已经实现了解密逻辑 private String doDecryption(String encryptedText, String key) { // 这里替换成你的解密代码 return "Decrypted with key " + key + ": [result]\n"; } // 测试示例 public static void main(String[] args) { BruteForceDecrypter decrypter = new BruteForceDecrypter("ABCDEFGHIKLMNOPQRSTUVWXYZ"); List<String> keys = decrypter.getPossibleKeys(2); // 生成所有2位长度的密钥 keys.forEach(System.out::println); } }
方法二:迭代实现(避免栈溢出)
如果密钥长度特别大(比如超过10),递归可能会触发栈溢出错误。这时候迭代法更稳妥——用队列来逐步构建组合,每次把当前长度的组合和字母表字符拼接,直到达到目标长度。
import java.util.ArrayList; import java.util.LinkedList; import java.util.List; import java.util.Queue; public class BruteForceDecrypter { private final String alphabet; public BruteForceDecrypter(String alphabet) { this.alphabet = alphabet; } public List<String> getPossibleKeys(int keyLength) { List<String> keys = new ArrayList<>(); Queue<String> queue = new LinkedList<>(); // 初始化队列:先加入所有1位长度的密钥 for (char c : alphabet.toCharArray()) { queue.add(String.valueOf(c)); } while (!queue.isEmpty()) { String currentKey = queue.poll(); int currentLength = currentKey.length(); if (currentLength == keyLength) { keys.add(currentKey); continue; } // 如果长度不够,拼接每个字母后加入队列 for (char c : alphabet.toCharArray()) { queue.add(currentKey + c); } } return keys; } // 其余方法(decrypt、doDecryption)和递归版本一致,这里省略 }
为什么这两种方法更优?
拿你的例子来说:字母表有25个字符,密钥长度为5时,总共有25^5 = 9765625个组合。如果先生成所有1-5长度的组合,总数会是25 + 25² + 25³ + 25⁴ + 25⁵ = 10172525,比直接生成5长度的多了40多万个无用组合。我们的方法完全避免了这些多余的计算,内存占用和运行效率都会更高。
小提醒:如果密钥长度过大(比如10以上),25^10是约9.5万亿个组合,这时候不管哪种方法都不现实,但作为学校项目,密钥长度应该不会这么夸张~
内容的提问来源于stack exchange,提问作者Maria Georgiou




