top1编程
← 返回题目
题解

破解密码

1 条题解

  • 0
    @ 2026-8-6 2:18:11

    P4851 破解密码(基础)

    解题思路

    第一步,理解题意。 密码是八位数字,从生日数字里按规则生成。规则是:先把第 1 个数字删除,再把新的第 1 个数字(也就是原来的第 2 个数字)放到数字序列的末尾。重复这个过程,直到所有数字都被删除。被删除的数字按顺序连起来,就是密码。

    第二步,类比排队。 这就像同学们排队做游戏:队伍最前面的人先出列,然后排在第二的人跑到队伍最后面重新排队,接着再让新队首出列……一直重复,直到队伍空了。出列的顺序连起来就是密码。这种"先进先出、队尾插入"的结构,就叫队列(queue)。

    第三步,用数组模拟队列。 用一个数组 q 当队列,head 指向队首,tail 指向队尾的下一个空位置。从 head 到 tail 之间的数字,就是当前还在队伍里的数字。

    第四步,按规则循环。 每一轮做两件事:先输出 q[head](第 1 个数字被删除),head 加 1;然后判断队伍里还有没有数字,如果有,就把现在的队首 q[head] 放到队尾 q[tail],再让 head 和 tail 都加 1。一直循环到 head 等于 tail,说明队伍空了。

    第五步,注意边界。 当队伍里只剩最后一个数字时,执行完"删除队首"后队伍就空了,不能再移动数字,所以要用 if (head < tail) 判断一下,防止数组越界。举个例子:输入 20230206,第 1 步删掉 2、把 0 移到末尾,第 2 步删掉 2、把 3 移到末尾……最后被删除的数字依次是 2、2、0、0、0、2、3、6,连起来就是密码 22000236,和样例一致。

    参考代码

    // 破解密码:每次删第1个、把第2个移到末尾,删掉的数字组成密码
    #include <iostream>
    using namespace std;
    int main() {
        char s[20];
        cin >> s;
        int q[100];        // 队列
        int n = 0;
        while (s[n] != '\0') {  // 把8位数字读入队列
            q[n] = s[n] - '0';
            n++;
        }
        int head = 0, tail = n;
        while (head < tail) {
            cout << q[head];    // 删除第1个数字
            head++;
            if (head < tail) {  // 还有数字,把新第1个移到末尾
                q[tail] = q[head];
                head++;
                tail++;
            }
        }
        cout << endl;
        return 0;
    }
    

    复杂度分析

    时间复杂度:每个数字只被删除一次、最多被移动一次,所以总操作次数与数字个数成正比,是 O(n)。n=8 是常数,运行非常快。

    空间复杂度:队列数组大小固定为 100,是 O(1)。

    • 1