3405. W的密码(北京大学考研机试题)

3405. W的密码

⭐️难度:简单(其实超级困难)

⭐️类型:字符串

📖题目:题目链接

Weird Wally 的无线部件公司(简称 W公司)能够生产各种各样的小型无线网络设备,从狗项圈到铅笔,再到钓鱼浮筒,一应俱全。这些小型设备的内存空间都十分有限,因此,像 Rijndael 这样的高级加密标准的加密算法虽然足够安全,但是并不适用。为了保障设备之间的信息传输有足够的安全性,W公司将使用以下加密算法,该算法需要你来实现。

加密消息需要三个整数密钥,k1、k2和 k3。

将字母 a∼i分为第一组,

字母 j∼r分为第二组,

字母 s∼z与下划线 _ 分为第三组。

在对消息进行加密时,要将消息中涉及到的每个组的字符,在组内进行向左旋转 ki 个位置(位于组内相对位置最左端的字符向左移动一位会到组内相对最右端的位置)。

每个组之间都是相互独立的,也就是说在旋转操作完成后,每个组的字符所占据的位置集合不会发生变化,只是组内各字符的相对位置可能发生变化。

解密即每个组内进行向右旋转 ki 位置。

例如,在 ki 值分别为 2,3,1时,对消息 the_quick_brown_fox 进行加密,我们可以得到加密后的字符串 _icuo_bfnwhoq_kxert。

下图显示了每个组中一个字符的解密右旋转。

观察加密后字符串中包含的全部第 1组(a∼i)的字符,可发现有 {i,c,b,f,h,e},分别位于位置 {2,3,7,8,11,17}。

在向右旋转 k1=2个位置后,字符的相对位置变为了 {h,e,i,c,b,f}。

下表显示了加密字符串依次完成第一组旋转解密、第二组旋转解密和第三组旋转解密后的具体字符串表示。

注意,在对其中一组字符进行旋转时,不会影响到其他组的字符。

现在,给定加密字符串和 k1,k2,k3的值,请你求出解密后的字符串。


输入样例:

2 3 1

_icuo_bfnwhoq_kxert

1 1 1

bcalmkyzx

3 7 4

wcb_mxfep_dorul_eov_qtkrhe_ozany_dgtoh_u_eji

2 4 3

cjvdksaltbmu

0 0 0

输出样例:

the_quick_brown_fox

abcklmxyz

the_quick_brown_fox_jumped_over_the_lazy_dog

ajsbktcludmv

🌟思路:

先理清楚题目,

以题目例子为例,先将字符串分组:

再将第一组单独抽出来进行左旋转2位,

第二组单独抽出来进行左旋转3位:

第三组单独抽出来进行左旋转2位:

最后三组旋转结果整合在一起:

与题目的结果一样。

以上是加密过程,题目要求解密,只需要把左旋转改成右旋转就行。

1️⃣分组

利用三个数组分别存储每个分组中的字符在原字符串中下标,方便后续进行旋转。

2️⃣🌟右旋转

右旋的写法

方案一:(空间复杂度低)

找到旋转边界,左边翻转一次,

右边翻转一次,

整体翻转一次。

方案二:(空间复杂度高)

方案二思路比较直接

🍎代码:

cpp 复制代码
// 难点:旋转
void youxuan(string& str, vector<int> vec, int k) {
    vector<char> tmp;
    if (vec.size() != 0 && k > vec.size()) {
        k = k % vec.size(); // 例如:数组长度为5,右移7位或者右移2位是一样的。
    }

    for (int i = vec.size() - k;i < vec.size();i++) { // 先保存右半部分,避免数据被覆盖
        tmp.push_back(str[ vec[i] ]); // 应存字符
    }

    for (int i = vec.size() - k - 1;i >= 0;i--) { // 旋转左部分
        str[ vec[i + k] ] = str[ vec[i] ];
    }

    for (int i = 0;i < k;i++) { // 旋转右部分
        str[ vec[i] ] = tmp[i];
    }
}

📚题解:

自己写:

cpp 复制代码
#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
#include<string.h>
#include<vector>  // vector不需要.h
#include<list>
#include<set>  // // 可以用 set 和 multiset
#include<unordered_set> // 可以用 unordered_set 和 unordered_multiset
#include<map>  // 可以用 map 和 multimap
#include<unordered_map> // 可以用 unordered_map 和 unordered_multimap
#include<algorithm>
#include<string>
#include<iostream>

using namespace std;

// 分组
void fenzu(string& str, vector<int>& vec1,vector<int>& vec2,vector<int>& vec3) {
    for (int i = 0;i < str.size();i++) {
        if (str[i] >= 'a' && str[i] <= 'i') {
            vec1.push_back(i); // 在原字符串中的下标压入数组
        }
        else if (str[i] >= 'j' && str[i] <= 'r') {
            vec2.push_back(i);
        }
        else {
            vec3.push_back(i);
        }
    }
}

// 难点:旋转
void youxuan(string& str, vector<int> vec, int k) {
    vector<char> tmp;
    if (vec.size() != 0 && k > vec.size()) {
        k = k % vec.size(); // 例如:数组长度为5,右移7位或者右移2位是一样的。
    }

    for (int i = vec.size() - k;i < vec.size();i++) { // 先保存右半部分,避免数据被覆盖
        tmp.push_back(str[ vec[i] ]); // 应存字符
    }

    for (int i = vec.size() - k - 1;i >= 0;i--) { // 旋转左部分
        str[ vec[i + k] ] = str[ vec[i] ];
    }

    for (int i = 0;i < k;i++) { // 旋转右部分
        str[ vec[i] ] = tmp[i];
    }
}

int main() {
   
    string str ;
    int k1, k2, k3;

    while (scanf("%d%d%d", &k1, &k2, &k3) != EOF) {
        if (k1 == 0 && k2 == 0 && k3 == 0) {
            break;
        }

        char arr[1000] = { 0 };
        scanf("%s", arr);
        str = arr;

        // 进行分组
        vector<int> vec1;
        vector<int> vec2;
        vector<int> vec3;
        fenzu(str, vec1, vec2, vec3);

        // 进行右旋转
        youxuan(str, vec1, k1);
        youxuan(str, vec2, k2);
        youxuan(str, vec3, k3);

        printf("%s\n", str.c_str());
    }

    return 0;
}

答案:

cpp 复制代码
 // t h e _ q u i c k _ b r o w n _ f o x
// 3 1 1 3 2 3 1 1 2 3 1 2 2 3 2 3 1 2 3
//   h e       i c     b           f    
//   i c       b f     h           e
//         q       k     r o   n     o  
//         o       n     o q   k     r
// t     _   u       _       w   _     x
// _     u   _       w       _   x     t
//


//   i c       b f     h           e
//         o       n     o q   k     r
// _     u   _       w       _   x     t
// _ i c u o _ b f n w h o q _ k x e r t

#include <vector>
#include <algorithm>
#include <stdio.h>
#include <string>
using namespace std;
void Partition(string str, vector<int>& vec1, vector<int>& vec2, vector<int>& vec3) {
    int i;
    for (i = 0; i < str.size(); ++i) {
        if (str[i] >= 'a' && str[i] <= 'i') {
            vec1.push_back(i);
        }
        else if (str[i] >= 'j' && str[i] <= 'r') {
            vec2.push_back(i);
        }
        else {
            vec3.push_back(i);
        }
    }
}
void RightRotate(string& str, vector<int>& vec, int offset) {
    vector<char> tmp;
    if (vec.size() != 0 && offset > vec.size()) {
		offset = offset % vec.size();
	}
    for (int i = vec.size() - offset; i < vec.size(); ++i) {
        tmp.push_back(str[vec[i]]);
    }
    for (int i = vec.size() - offset - 1; i >= 0; --i) {
        str[vec[i + offset]] = str[vec[i]];
    }
    for (int i = 0; i < tmp.size(); ++i) {
        str[vec[i]] = tmp[i];
    }
}
int main() {
    string str;
    int k1, k2, k3;
    while (scanf("%d%d%d", &k1, &k2, &k3) != EOF) {
        if (k1 == 0 && k2 == 0 && k3 == 0) {
            break;
        }
        char arr[1000] = { 0 };
        scanf("%s", arr);
        str = arr;

        vector<int> vec1, vec2, vec3;
        // vec1 存储1分组在str中的下标
        Partition(str, vec1, vec2, vec3);
        RightRotate(str, vec1, k1);
        RightRotate(str, vec2, k2);
        RightRotate(str, vec3, k3);

        printf("%s\n", str.c_str());
    }
    
    return 0;
}
相关推荐
hnjzsyjyj21 小时前
洛谷 AT_abc269_b [ABC269B]:Rectangle Detection
字符串
闲人编程4 天前
内存数据库性能调优
数据库·redis·字符串·高并发·哈希·内存碎片
Tisfy6 天前
LeetCode 761.特殊的二进制字符串:分治(左右括号对移动)
算法·leetcode·字符串·递归·分治
hnjzsyjyj9 天前
洛谷 P8738:[蓝桥杯 2020 国 C] 天干地支 ← string
蓝桥杯·字符串·天干地支
闻缺陷则喜何志丹11 天前
【C++DFS 马拉车】3327. 判断 DFS 字符串是否是回文串|2454
c++·算法·深度优先·字符串·力扣·回文·马拉车
Tisfy11 天前
LeetCode 3714.最长的平衡子串 II:前缀和(一二三分类)
算法·leetcode·前缀和·字符串·题解
码农幻想梦12 天前
PKUKY150 浮点数加法(北京大学考研机试真题)
考研·字符串
远方23516 天前
哈希计算器1.0
字符串·md5·哈希·sha256