文章

【GESP】C++三级真题 luogu-B3843 [GESP202306 三级] 密码合规

GESP三级真题,字符串相关,难度★★✮☆☆。

luogu-B3843 [GESP202306 三级] 密码合规

题目要求

题目描述

网站注册需要有用户名和密码,编写程序以检查用户输入密码的有效性。合规的密码应满足以下要求 :。

  1. 只能由 $\texttt a \sim \texttt z$ 之间 $26$ 个小写字母、$\texttt A \sim \texttt Z$ 之间 $26$ 个大写字母、$0 \sim 9$ 之间 $10$ 个数字以及 !@#$ 四个特殊字符构成。

  2. 密码最短长度 $:6$ 个字符,密码最大长>度 $:12$ 个字符。

  3. 大写字母,小写字母和数字必须至少有其中两种,以及至少有四个特殊字符中的一个。

输入格式

输入一行不含空格的字符串。约定长度不超过 $100$。该字符串被英文逗号分隔为多段,作为多组被检测密码。

输出格式

输出若干行,每行输出一组合规的密码。输出顺序以输入先后为序,即先输入则先输出。

输入输出样例 #1

输入 #1

1
seHJ12!@,sjdkffH$123,sdf!@&12HDHa!,123&^YUhg@!

输出 #1

1
2
seHJ12!@
sjdkffH$123

说明/提示

【样例 1 解释】

输入被英文逗号分为了四组被检测密码:seHJ12!@sjdkffH$123sdf!@&12HDHa!123&^YUhg@!。其中 sdf!@&12HDHa! 长度超过 12 个字符,不合规;123&^YUhg@! 包含四个特殊字符之外的字符不合规。


题目分析

解题思路

  1. 读取输入字符串并按逗号分割:
    • 使用getline读取一行输入
    • 遍历字符串,按逗号分割成多个密码字符串
    • 将分割后的密码存入数组
  2. 检查每个密码的合规性:
    • 检查密码长度是否在6-12个字符之间
    • 检查是否只包含合法字符(小写字母、大写字母、数字、特殊字符!@#$)
    • 统计包含的字符类型:
      • 小写字母(a-z)
      • 大写字母(A-Z)
      • 数字(0-9)
      • 特殊字符(!@#$)
    • 验证是否满足至少两种字母/数字和至少一个特殊字符的要求
  3. 输出合规密码:
    • 按输入顺序输出所有合规的密码
    • 每个密码占一行

复杂度分析:

  • 时间复杂度:$O(n×m)$,其中n为输入字符串总长度,m为单个密码的最大长度
  • 空间复杂度:$O(n)$,需要存储分割后的密码字符串


示例代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
#include <iostream>
#include <string>

int main() {
    // 读取输入字符串
    std::string input;
    getline(std::cin, input);

    // 用于存储分割后的密码
    int count = 0;
    std::string cur_pwd;
    std::string str_ary[100] = {""};
    int ary_len = 0;

    // 按逗号分割输入字符串
    for (int i = 0; i < input.length(); i++) {
        if (input[i] == ',') {
            cur_pwd = input.substr(i - count, count);
            str_ary[ary_len] = cur_pwd;
            ary_len++;
            count = 0;
        } else {
            count++;
        }
        // 处理最后一个密码
        if (i == input.length() - 1) {
            cur_pwd = input.substr(i - count + 1, count);
            str_ary[ary_len] = cur_pwd;
            ary_len++;
        }
    }

    // 遍历检查每个密码
    for (int i = 0; i < ary_len; i++) {
        bool flag = true;
        std::string cur = str_ary[i];
        
        // 检查密码长度
        if (cur.length() < 6 || cur.length() > 12) {
            flag = false;
            continue;
        }

        // 记录密码包含的字符类型
        int type[4] = {0}; // 0:小写字母 1:大写字母 2:数字 3:特殊字符
        
        // 遍历密码中的每个字符
        for (int j = 0; j < str_ary[i].length(); j++) {
            if (cur[j] >= 'a' && cur[j] <= 'z') {
                type[0] = 1;
            } else if (cur[j] >= 'A' && cur[j] <= 'Z') {
                type[1] = 1;
            } else if (cur[j] >= '0' && cur[j] <= '9') {
                type[2] = 1;
            } else if (cur[j] == '!' || cur[j] == '@' || cur[j] == '#' ||
                       cur[j] == '$') {
                type[3] = 1;
            } else {
                // 包含非法字符
                flag = false;
                break;
            }
        }

        if (!flag) {
            continue;
        }

        // 统计字符类型数量
        int sum = 0;
        for (int k = 0; k < 3; k++) {
            sum += type[k];
        }

        // 检查是否满足字符类型要求
        if (sum < 2 || type[3] == 0) {
            flag = false;
            continue;
        }

        // 输出合规密码
        std::cout << cur << std::endl;
    }
    return 0;
}

所有代码已上传至Github:https://github.com/lihongzheshuai/yummy-code

GESP各级别考纲要点、知识拓展和练习题目清单详见C++学习项目主页

luogu-”系列题目已加入洛谷Java、C++初学团队作业清单,可在线评测,团队名额有限,欢迎加入。

bcqm-”系列题目可在编程启蒙题库进行在线评测。

本文由作者按照 CC BY 4.0 进行授权