Caesar Cipher凯撒密码

题目如下:(注意可能不按字典序排列)
在这里插入图片描述
这些入门算法题处境很尴尬,大佬轻松ac,像我这种小白查了半天资料不知道怎么搞,这样一来,我这种弱鸡网上就没得嫖 ,蒟蒻玩家表示初学很心累。
主要是kmp算法,如果不懂参考这篇文章:什么是kmp算法
先说下题意吧,给出字符A,明文w,和加密文s,在s中单词w只会出现一次(注意题目黑体字,英语不好我纳闷这题很久 ),输出位移密码即可。
当然先处理字符串,A中只包含a-z;A-Z;0-9;这些都是ascii码表中字符,凯撒密码按照一个shift值来排密码,此处不一定按字典序,比如三例D7a,有三种可能对应情况,位移0,1,2。
也就是说把w中的D7a字符换成D7a,7aD,aD7;(为什么要换w?因为我喜欢爱好 ,因为w不超过50000而text S大小500000)在s中查找w换掉任一项字符串即可,这样位移为1的时候,D7a换成7aD,只出现了一次,位移为2时,D7a换成a7D,在s中只出现一次。
怎么换呢?从A中去查对应位移后字符 ,这显然查到超时了,既然A中字符就26+26+10个,那直接建立一个62大小数组按顺序把a-z;A-Z;0-9替换即可,当然这些都是ascii表中数字,直接建立一个128大小的数组来换也不算耗空间,而且简单。
定义一个int型ascii[128]数组,比如D7a位移1位是7aD,这样‘D’会换成‘7’字符,(D的坐标加1就是7的位置)只需要在‘D’位置(字符’D’转成int型是68)换成‘7’字符大小即可。

for (int i = 0; i < la; i++) {
				ord1 = a[i];
				ord2 = a[(i + k) % la];//k是位移数,la是字符串A的长度
				ascii[ord1] = ord2 ;//ascii数组用来转换字符
			}

然后转换w字符串


			for (int i = 0; i < lw; i++) {//lw是w字符串长度
				nw[i] =ascii[w[i]];
			}

这样用nw和S进行kmp查找,查找到出现大于一次就返回重新把位移k++,如果等于一次就说明这个位移k就是密码。0次说明密码不对,k++;
ac代码(这个时间复杂度还是比较高O(n2),直接用的板子kmp返回字符串x在y中出现次数,因为太菜越改越多bug ,大佬可能做法更巧妙)

#include<iostream>
#include<string.h>
#include<cstdio>
using namespace std;
const int maxn = 1000005;
int nxt[maxn];
void getnext(char *s)
{
	int i = 0, j = -1, len = strlen(s);
	nxt[0] = -1;
	while (i < len)
	{
		if (j == -1 || s[i] == s[j])
		{
			if (s[++i] == s[++j])    nxt[i] = nxt[j];
			else    nxt[i] = j;
		}
		else    j = nxt[j];
	}
}

int kmp(char *x, char *y)
{
	getnext(x);
	int i = 0, j = 0, ans = 0, leny = strlen(y), lenx = strlen(x);
	while (i < leny)
	{
		if (j == -1 || x[j] == y[i])
		{
			i++, j++;
			if (j == lenx)
			{
				ans++;
				j = nxt[j];
			}
		}
		else    j = nxt[j];
	}
	return ans;/实际上不用返回次数,定义一个bool型在循环体内部判断ans>1就返回false减少查找
}


int main() {
	int n;
	char a[65];
	int aa[65];
	char w[50005], t[500005];
	char nw[50005];
	int ascii[128];
	int ord1, ord2;
	cin >> n;
	while (n--) {
		cin >> a >> w >> t;
		int la = strlen(a);
		int lw = strlen(w);
		int lt = strlen(t);
		int num = 0;//num统计解的个数
		for (int k = 0; k < la; k++) {//k表示位移,只能是0~A的长度-1;
			for (int i = 0; i < la; i++) {
				ord1 = a[i];
				ord2 = a[(i + k) % la];
				ascii[ord1] = ord2 ;
			}
			for (int i = 0; i < lw; i++) {
				nw[i] =ascii[w[i]];
			}
			nw[lw] = '\0';
			if (kmp(nw, t)==1) {
				aa[num++] = k;
			}
		}
		if (num == 0)cout << "no solution" << endl;
		else if (num == 1)cout << "unique: " << aa[0] << endl;
		else {
			printf("ambiguous:");
			for (int i = 0; i < num; i++) {
				printf(" %d", aa[i]);
			}
			printf("\n");
		}
	}


	return 0;
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
母串进行加密,输出密文。凯撒密码算法是一种简单的加密算法,通过对每个字符加上一个偏移量k来得到密文。因此,将输入的字符转换为ASCII码,然后将其加上k,再将结果转换为字符即可得到密文。 具体步骤如下: 1. 接受一个数字,作为秘钥k。 2. 接受需要加密的字符串。 3. 对于字符串中的每一个字符,将其转换为ASCII码,并加上k偏移量。 4. 将偏移后的结果转换为对应的字符,并将其存入一个结果字符串中。 5. 输出加密后的结果字符串作为密文。 需要注意的是,为了保证加密后的结果可以被正常解密,加密和解密所使用的秘钥必须相同。因此,在解密时需要使用相同的偏移量,将密文中的每个字符减去k,再转换为对应的字符即可得到原文。 实现这个算法可以选择不同的编程语言,比如Python、Java等。下面是一个Python实现的示例代码: ```python def caesar_cipher(message, k): result = "" for char in message: if char.isalpha(): # 如果字符是字母则进行偏移操作 offset = 65 if char.isupper() else 97 # 根据大小写确定偏移量 cipher = chr((ord(char) - offset + k) % 26 + offset) # 进行偏移操作 result += cipher else: # 如果不是字母则直接加入结果字符串 result += char return result message = "Hello, World!" k = 3 cipher_text = caesar_cipher(message, k) print(cipher_text) # 输出加密后的结果 plain_text = caesar_cipher(cipher_text, -k) # 解密需要使用相反的偏移量 print(plain_text) # 输出解密后的原文 ``` 上述代码在加密时将偏移量应用到字符串中的每个字母上,并将结果存入一个结果字符串中。在解密时使用相反的偏移量将密文中的每个字符还原为原来的字符,最终得到原文。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值