You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

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

火山引擎 最新活动