跟参数输出范例一样就行。得用他给的变量名。其它就是凯撒密码的形式,变成不需要key就行破译,根据图片里的频率(那个表格就是给出的频率)
package com.zhengtao;
/*
* @Description :
* @CreateTime : 2022-02-25 15:36
*/
public class Demo {
/**
* 这个 是 明文?
*/
public static final double[] ENGLISH = {
0.0855, 0.0160, 0.0316, 0.0387, 0.1210, 0.0218, 0.0209, 0.0496, 0.0733,
0.0022, 0.0081, 0.0421, 0.0253, 0.0717, 0.0747, 0.0207, 0.0010, 0.0633,
0.0673, 0.0894, 0.0268, 0.0106, 0.0183, 0.0019, 0.0172, 0.0011
};
/*
* @Description: 这个 main 方法用来破解 凯撒密码
* 首先了解,什么是凯撒密码,凯撒加密(Caesar Code)是一种简单的消息编码方式:它根据字母表将消息中的每个字母移动常量位k。
* 举个例子如果k等于3,则在编码后的消息中,每个字母都会向前移动3位:a会被替换为d;b会被替换成e;
* 依此类推。字母表末尾将回卷到字母表开头。于是,w会被替换为z, x会被替换为a。在解码消息的时候,每个字母会反方向移动同样的位数。
* 那么 如何破解 凯撒密码,已经很简单明了了,
* @Date: 2022-02-25 16:00
* @param args
* @Return: void
*/
public static void main(String[] args) {
// 这里应该是从命令行读取的,我这里,不方便 从命令行读取,我直接写死了,题主 这里自己处理一下
String ciphertext = "asjfkljasklfjlkasjdklfjklaskldjfasfdd";
// 从题目中看, EngLish 应该是,最终比对的明文
// 手动实现 解密凯撒密码
String temp = "";
int count = 1;
while(true){
temp = "";
for (int i = 0; i < ciphertext.length(); i++) {
// 确保 输入的字母 是 字母
if ((ciphertext.charAt(i) > 'a' && ciphertext.charAt(i) < 'z') || (ciphertext.charAt(i) > 'A' && ciphertext.charAt(i) < 'Z')){
char ch = (char) (ciphertext.charAt(i) + count);
// 凯撒编码
if (ch > 106 && ch < 97){
ch = (char) (ch - 26);
}
if (ch > 122){
int l = ch - 97;
ch = (char) (ch - 26);
}
temp = ch + temp;
}
}
count++;
System.out.println("开始执行 -> " + temp);
if (chiSquared(frequency(temp), ENGLISH) == 0){
break;
}
if (count == 26){
temp = "";
break;
}
}
if (temp.equals("")){
System.out.println("输入与明文不对应");
}else {
System.out.println("破解成功 -> " + temp);
}
}
/*
* @Description: 返回 String 中 每个字母出现的次数
* @Date: 2022-02-25 15:37
* @param str
* @Return: int[]
*/
public static int[] count(String str){
int[] res = new int[26];
char[] chars = str.toCharArray();
for (char ch : chars) {
// 小写字母
if(ch - 65 >= 0 && ch - 65 <=25){
res[ch - 65]++;
}
// 大写字母
if (ch - 97 >= 0 && ch - 97 <= 25){
res[ch - 97]++;
}
}
return res;
}
public static double[] frequency(String str){
double[] res = new double[26];
// 每个字母出现的频率
int[] count = count(str);
// 给定字符串的长度
int length = str.length();
for (int i = 0; i < count.length; i++) {
res[i] = count[i] / length;
}
return res;
}
/**
* @Description: 求出来 两个数组到底有多接近 如果两个数组,一模一样,则返回结果 为 0, 匹配度越高,则返回值 越小
* @Date: 2022-02-25 15:53
* @param freq
* @param english
* @Return: double
*/
public static double chiSquared(double[] freq, double[] english){
if (freq.length != english.length){
return -1;
}
double res = 0.0;
double[] temp = new double[26];
// 求出 a - z的匹配度
for (int i = 0; i < freq.length; i++) {
temp[i] = (freq[i] - english[i]) * (freq[i] - english[i]) / english[i];
}
// 根据公式,将结果求和
for (double v : temp) {
res += v;
}
return res;
}
}
看不太清楚