题解:洛谷 P1914 小书童——凯撒密码
【题目来源】
【题目描述】
蒟蒻虽然忘记密码,但他还记得密码是由一个字符串组成。密码是由原文字符串(由不超过 \(50\) 个小写字母组成)中每个字母向后移动 \(n\) 位形成的。z 的下一个字母是 a,如此循环。他现在找到了移动前的原文字符串及 \(n\),请你求出密码。
【输入】
第一行:\(n\)。第二行:未移动前的一串字母。
【输出】
一行,是此蒟蒻的密码。
【输入样例】
1
qwe
【输出样例】
rxf
【核心思想】
-
问题分析:给定一个由小写字母组成的字符串(长度不超过 50)和一个整数 \(n\),需要将每个字母向后移动 \(n\) 位,形成凯撒密码。当移动超过
'z'时,从'a'重新开始(循环移位)。本质是字符串的循环移位问题,利用模运算处理边界。 -
算法选择:
- 遍历 + 模运算:对每个字符,将其转换为 0~25 的数字(
'a'对应 0),加上 \(n\) 后对 26 取模,再转换回字符。这是最通用且安全的方法。 - 边界判断(备选):也可以像代码中那样,先尝试直接加 \(n\),若超过
'z'则用模运算修正。但使用统一模运算更简洁。
- 遍历 + 模运算:对每个字符,将其转换为 0~25 的数字(
-
关键步骤:
- 读入:读取 \(n\) 和字符串 \(s\)。
- 遍历并转换:对于每个字符 \(s[i]\):
- 计算偏移后的字符:
s[i] = (s[i] - 'a' + n) % 26 + 'a'。
- 计算偏移后的字符:
- 输出:输出转换后的字符串。
-
时间/空间复杂度:
- 时间复杂度:\(O(L)\),其中 \(L\) 是字符串长度。
- 空间复杂度:\(O(1)\),在原字符串上直接修改。
-
字符串与模运算:
- 模运算处理循环:将字母映射到 0~25 的整数,加 \(n\) 后对 26 取模,可以自然处理
'z'到'a'的循环。 - \(n\) 的范围:题目未明确 \(n\) 的范围,但模运算可以处理任意整数 \(n\)(包括负数,但本题 \(n\) 为正整数)。
- 适用场景:凯撒密码是古典密码学中最简单的加密方式,也是字符串处理入门常见题。
- 模运算处理循环:将字母映射到 0~25 的整数,加 \(n\) 后对 26 取模,可以自然处理
【算法标签】
入门 #字符串入门
【代码详解】
#include <bits/stdc++.h> // 包含标准库头文件(万能头文件)
using namespace std; // 使用标准命名空间
int main()
{
int n; // 定义变量:字母位移量
string s; // 定义字符串:存储待加密的字符串
cin >> n >> s; // 输入位移量和字符串
// 遍历字符串中的每个字符
for (int i = 0; i < s.length(); i++)
{
// 判断字符位移后是否仍在字母z范围内
if (s[i] + n <= 'z')
{
// 直接进行位移
s[i] += n;
}
else
{
// 处理越界情况,使用模运算实现循环位移
// (n-26)%26 确保位移量在合理范围内
s[i] = s[i] + (n - 26) % 26;
}
}
cout << s; // 输出加密后的字符串
return 0; // 程序正常结束
}
【运行结果】
1
qwe
rxf
浙公网安备 33010602011771号