[蓝桥杯]密文搜索

密文搜索

题目描述

福尔摩斯从 X 星收到一份资料,全部是小写字母组成。

他的助手提供了另一份资料:许多长度为 8 的密码列表。

福尔摩斯发现,这些密码是被打乱后隐藏在先前那份资料中的。

请你编写一个程序,从第一份资料中搜索可能隐藏密码的位置。要考虑密码的所有排列可能性。

输入描述

输入第一行:一个字符串 ss,全部由小写字母组成,长度小于 1024*1024。

紧接着一行是一个整数 nn,表示以下有 nn 行密码,1≤n≤10001≤n≤1000。

紧接着是 nn 行字符串,都是小写字母组成,长度都为 8。

输出描述

输出一个整数, 表示每行密码的所有排列在 ss 中匹配次数的总和。

输入输出样例

示例

输入

aaaabbbbaabbcccc
2
aaaabbbb
abcabccc

输出

4

运行限制

  • 最大运行时间:3s
  • 最大运行内存: 512M

总通过次数: 821  |  总提交次数: 975  |  通过率: 84.2%

难度: 困难   标签: 2015, 国赛

算法思路:滑动窗口 + 频率哈希

本问题要求在长字符串中高效搜索多个长度为8的密码的所有排列出现的总次数。核心挑战在于避免枚举所有排列组合(8! = 40320),采用​​字符频率统计+滑动窗口优化​​策略:

 

图片

代码

 

graph TD A[输入主串s和密码列表] --> B[密码预处理] B --> C[频率向量→字符串<br>存入哈希表] C --> D[初始化窗口0-7] D --> E[更新频率字符串<br>查询哈希表] E --> F[滑动窗口:移左字符+移右字符] F --> G[更新两个字符频率] G --> E E --> H[累加匹配次数] H --> I[输出总和]

输入主串s和密码列表

密码预处理

频率向量→字符串
存入哈希表

初始化窗口0-7

更新频率字符串
查询哈希表

滑动窗口:移左字符+移右字符

更新两个字符频率

累加匹配次数

输出总和

算法步骤

  1. ​频率向量表示排列​​:两个字符串互为排列当且仅当字符频率相同。将每个密码表示为26维频率向量(a~z的计数)。
  2. ​密码预处理​​:计算每个密码的频率向量,转换为26字符的字符串(如 "400400..."),存入哈希表记录出现次数。
  3. ​滑动窗口扫描​​:
    • 初始化窗口(0~7)的频率向量
    • 窗口右移时,仅更新移出字符(左边界)和移入字符(右边界)的频率
    • 实时更新频率字符串,查询哈希表累加匹配次数
  4. ​优化关键​​:维护动态频率字符串,避免每次重新生成。

    算法思路:滑动窗口 + 频率哈希

    本问题要求在长字符串中高效搜索多个长度为8的密码的所有排列出现的总次数。核心挑战在于避免枚举所有排列组合(8! = 40320),采用​​字符频率统计+滑动窗口优化​​策略:

  5. ​频率向量表示排列​​:两个字符串互为排列当且仅当字符频率相同。将每个密码表示为26维频率向量(a~z的计数)。
  6. ​密码预处理​​:计算每个密码的频率向量,转换为26字符的字符串(如 "400400..."),存入哈希表记录出现次数。
  7. ​滑动窗口扫描​​:
    • 初始化窗口(0~7)的频率向量
    • 窗口右移时,仅更新移出字符(左边界)和移入字符(右边界)的频率
    • 实时更新频率字符串,查询哈希表累加匹配次数
  8. ​优化关键​​:维护动态频率字符串,避免每次重新生成。
  9. ​密码预处理​​(O(n×26))
    • 对每个密码,统计a~z频率(26维数组)
    • 频率数组转为26字符字符串(如 [4,4,0,...] → "440..."
    • 哈希表记录频率字符串出现次数
  10. ​窗口初始化​​(O(26))
    • 计算主串前8字符的频率数组
    • 生成初始频率字符串
  11. ​滑动窗口​​(O(|s|×2))
    • 移出左边界字符:对应频率减1,更新频率字符串
    • 移入右边界字符:对应频率加1,更新频率字符串
    • 查询哈希表累加匹配次数
  12. ​结果输出​​:总匹配次数

算法步骤

  1. ​密码预处理​​(O(n×26))
    • 对每个密码,统计a~z频率(26维数组)
    • 频率数组转为26字符字符串(如 [4,4,0,...] → "440..."
    • 哈希表记录频率字符串出现次数
  2. ​窗口初始化​​(O(26))
    • 计算主串前8字符的频率数组
    • 生成初始频率字符串
  3. ​滑动窗口​​(O(|s|×2))
    • 移出左边界字符:对应频率减1,更新频率字符串
    • 移入右边界字符:对应频率加1,更新频率字符串
    • 查询哈希表累加匹配次数
  4. ​结果输出​​:总匹配次数

代码实现(C++)

#include <iostream>
#include <vector>
#include <unordered_map>
using namespace std;int main() {ios::sync_with_stdio(false);cin.tie(0);string s;cin >> s;int n;cin >> n;// 1. 密码预处理:频率数组→字符串unordered_map<string, int> count_map;for (int i = 0; i < n; i++) {string pwd;cin >> pwd;vector<int> freq(26, 0);for (char c : pwd) freq[c - 'a']++;string key(26, '0');for (int j = 0; j < 26; j++) key[j] = '0' + freq[j]; // 频率转字符count_map[key]++;}// 2. 处理边界:主串长度不足8int len = s.size();if (len < 8) {cout << 0 << endl;return 0;}// 3. 初始化窗口频率vector<int> win_freq(26, 0);string win_key(26, '0');for (int i = 0; i < 8; i++) {int idx = s[i] - 'a';win_freq[idx]++;win_key[idx] = '0' + win_freq[idx]; // 动态更新}// 4. 滑动窗口扫描long long total = count_map[win_key]; // 初始窗口匹配for (int i = 1; i <= len - 8; i++) {// 移出左边界字符int idx_out = s[i-1] - 'a';win_freq[idx_out]--;win_key[idx_out] = '0' + win_freq[idx_out];// 移入右边界字符int idx_in = s[i+7] - 'a';win_freq[idx_in]++;win_key[idx_in] = '0' + win_freq[idx_in];total += count_map[win_key]; // 查询累加}cout << total << endl;return 0;
}

代码解析

  1. ​密码预处理​​(L15-25)
    • freq[26]:存储a~z频率(freq[0]=a
    • key:26字符字符串(key[0]='4'表示a出现4次)
    • count_map:记录频率字符串出现次数
  2. ​窗口初始化​​(L35-41)
    • win_freq:窗口频率数组
    • win_key:动态更新的频率字符串
  3. ​滑动窗口​​(L44-57)
    • ​移出字符​​:左边界s[i-1]频率减1,更新win_key对应位置
    • ​移入字符​​:右边界s[i+7]频率加1,更新win_key对应位置
    • ​查询累加​​:直接访问count_map
  4. ​复杂度分析​
    • 时间:O(n×26 + |s|×2) ≈ O(26,000 + 2,000,000) = 2.03e6(1e6主串)
    • 空间:O(n×26) ≈ 26,000(1000密码)

实例验证

​输入​​:

aaaabbbbaabbcccc
2
aaaabbbb    → 频率字符:'4','4','0',...(24个0)
abcabccc    → 频率字符:'2','2','4','0',...(23个0)

​执行过程​​:

窗口位置子串频率字符串匹配密码累加值
0-7aaaabbbb44000...密码11
1-8aaabbbba44000...密码12
2-9aabbbbaa44000...密码13
8-15aabbcccc22400...密码24

​输出​​:4 ✓

注意事项

  1. ​边界处理​​:
    • 主串长度 <8 时直接返回0
    • 窗口右边界 i+7 需满足 i ≤ len-8
  2. ​频率转换​​:
    • 密码字符必须小写(c-'a'索引0~25)
    • 频率范围0~8('0'+freq 不会溢出)
  3. ​哈希冲突​​:
    • 不同频率数组可能生成相同字符串(概率极低)
    • 可改用vector作为键(需自定义哈希)

多方位测试点

​测试类型​​输入样例​​预期输出​​验证要点​
主串不足8字符"abc", 1, "abcdefgh"0边界处理
单密码全匹配"aaaaaaaa", 1, "aaaaaaaa"9重叠窗口计数
多密码相同频率两密码频率相同双倍计数哈希表累计验证
零匹配"abcdefgh", 1, "zzzzzzzz"0无匹配处理
最大规模1e6长度主串, 1000密码约1e6次操作时间效率(<0.5s)
特殊字符分布"abcdabcd", 1, "aabbccdd"1频率计算正确性

优化建议

  1. ​向量哈希替代字符串​​:
    struct VectorHash {size_t operator()(const vector<int>& v) const {size_t seed = 0;for (int x : v) seed ^= hash<int>()(x) + 0x9e3779b9 + (seed<<6) + (seed>>2);return seed;}
    };
    unordered_map<vector<int>, int, VectorHash> count_map; // 避免字符串转换
  2. ​并行化处理​​:
    #pragma omp parallel for reduction(+:total)
    for (int i = 0; i <= len-8; i++) {// 各窗口独立计算
    }
  3. ​内存优化​​:
    • 链式前向星存储频率表(减少vector开销)
    • 预分配哈希表桶数量:count_map.reserve(n)

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.pswp.cn/bicheng/83631.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

打卡第36天:模型可视化以及推理

知识点回顾&#xff1a; 1.三种不同的模型可视化方法&#xff1a;推荐torchinfo打印summary权重分布可视化 2.进度条功能&#xff1a;手动和自动写法&#xff0c;让打印结果更加美观 3.推理的写法&#xff1a;评估模式 作业&#xff1a;调整模型定义时的超参数&#xff0c;对…

8天Python从入门到精通【itheima】-68(元组)

目录 65节——元组的定义和操作 1.学习目标 2.为什么要学习元组 3.元组的定义 4.定义元组的注意事项 5.元组的嵌套 6.元组的相关操作 【1】index方法 【2】count方法 【3】len方法 7.元组的遍历 【1】while循环进行元组的遍历 【2】for循环进行元组的变量 Python …

链表题解——环形链表【LeetCode】

141. 环形链表 方法一 核心思想&#xff1a; 使用一个集合 seen 来记录已经访问过的节点。遍历链表&#xff0c;如果当前节点已经存在于集合中&#xff0c;说明链表存在环&#xff1b;否则&#xff0c;将当前节点添加到集合中&#xff0c;继续遍历。如果遍历结束&#xff08;h…

【免费数据】1980-2022年中国2384个站点的水质数据

水&#xff0c;是生命之源&#xff0c;关乎着地球上每一个生物的生存与发展。健康的水生生态系统维持着整个水生态的平衡与活力&#xff1b;更是确保人类能持续获得清洁水源的重要保障。水质数据在水质研究、海洋生物量测算以及生物多样性评估等诸多关键领域都扮演着举足轻重的…

分享推荐高精度磁阻式磁编码器芯片

磁编码器其通过感应旋转磁场来实现角度、转速的测量&#xff0c;因此&#xff0c;相较于传统的光编码器&#xff0c;磁编码器对粉尘、污垢和油脂等污染物有很强的耐受性&#xff0c;即使在较为恶劣的环境中仍能够保持高分辨率与检测精度&#xff0c;安装和维护简捷方便&#xf…

Spring AI 项目实战(四):Spring Boot + AI + DeepSeek 超参数优化——智能化机器学习平台(附完整源码)

系列文章 序号文章名称1Spring AI 项目实战&#xff08;一&#xff09;&#xff1a;Spring AI 核心模块入门2Spring AI 项目实战&#xff08;二&#xff09;&#xff1a;Spring Boot AI DeepSeek 深度实战&#xff08;附完整源码&#xff09;3Spring AI 项目实战&#xff08…

高效VLM:VisionZip

论文&#xff1a;[2412.04467] VisionZip: Longer is Better but Not Necessary in Vision Language Models github&#xff1a;https://github.com/dvlab-research/VisionZip LLaVA论文&#xff1a;https://arxiv.org/abs/2310.03744 LLaVA仓库&#xff1a;https://github.…

华为设备OSPF配置与实战指南

一、基础配置架构 sysname HUAWEI-ABR ospf 100 router-id 1.1.1.1area 0.0.0.0network 10.1.1.0 0.0.0.255 # 将接口加入区域0 interface GigabitEthernet0/0/1ospf enable 100 area 0.0.0.0 # 华为支持点分十进制区域号bandwidth-reference 10000 # 设置10Gbps参考带宽…

区块链架构深度解析:从 Genesis Block 到 Layer 2

# 区块链架构深度解析&#xff1a;从 Genesis Block 到 Layer 2 目录 一、Genesis Block&#xff1a;区块链的起点 二、Layer 0&#xff1a;区块链的底层网络架构 三、Layer 1&#xff1a;核心协议层 &#x1f680; 四、Layer 2&#xff1a;扩展性解决方案 五、未来展望&a…

【位运算】丢失的数字(easy)

34. 丢失的数字&#xff08;easy&#xff09; 题⽬描述&#xff1a;方法一&#xff1a;排序解法&#xff08;位运算&#xff09;&#xff1a;C 算法代码&#xff1a;Java 算法代码&#xff1a; 题⽬链接&#xff1a; 268. 丢失的数字 题⽬描述&#xff1a; 给定⼀个包含 [0, n…

如何通过RL真正提升大模型的推理能力?NVIDIA提出长期强化学习训练框架ProRL

原文&#xff1a;https://mp.weixin.qq.com/s/QLFKvb8Ol3CX9uWKBXSrow 论文&#xff1a;ProRL: Prolonged Reinforcement Learning Expands Reasoning Boundaries in Large Language Models Abs&#xff1a;https://arxiv.org/abs/2505.24864 权重下载&#xff1a;https://hugg…

ORM 框架的优缺点分析

ORM 框架的优缺点分析 一、ORM 框架概述 ORM(Object-Relational Mapping)是一种将关系型数据库与面向对象编程进行映射的技术框架。它通过将数据库表映射为编程语言中的类,将记录映射为对象,将字段映射为属性,实现了用面向对象的方式操作数据库。 核心价值:ORM 在数据库和…

1. 数据库基础

1.1 什么是数据库 ⭐ mysql 本质是一种网络服务, 是基于 C(mysql) S(mysqld)的 网络服务. 存储数据用文件就可以了&#xff0c;为什么还要弄个数据库&#xff1f;文件保存数据存在以下缺点&#xff1a; 文件的安全性问题。文件不利于数据查询和管理。文件不利于存储海量数据。…

go语言学习 第5章:函数

第5章&#xff1a;函数 函数是编程中不可或缺的一部分&#xff0c;它封装了一段可重复使用的代码&#xff0c;用于执行特定的任务。在Go语言中&#xff0c;函数同样扮演着重要的角色。本章将详细介绍Go语言中函数的定义、调用、参数传递、返回值处理以及一些高级特性&#xff…

MapReduce 分布式计算模型

what&#xff1a;分解大数据集&#xff0c;并行处理&#xff0c;汇总结果&#xff08;分解组合思想&#xff09; 目的&#xff1a;SQL查询转换为MR&#xff0c;理解MR更好优化SQL 优点&#xff1a; 只需关注业务逻辑&#xff08;自定义函数map&#xff0c;reduce&#xff09…

RDMA简介3之四种子协议对比

RDMA协议共有四种子协议&#xff0c;分别为InfiniBand、iWARP、RoCE v1和RoCE v2协议。这四种协议使用统一的RDMA API&#xff0c;但在具体的网络层级实现上有所不同&#xff0c;如图1所示&#xff0c;接下来将分别介绍这四种子协议。 图1 RDMA四种子协议网络层级关系图 Infin…

LabelImg: 开源图像标注工具指南

LabelImg: 开源图像标注工具指南 1. 简介 LabelImg 是一个图形化的图像标注工具&#xff0c;使用 Python 和 Qt 开发。它是目标检测任务中最常用的标注工具之一&#xff0c;支持 PASCAL VOC 和 YOLO 格式的标注输出。该工具开源、免费&#xff0c;并且跨平台支持 Windows、Lin…

系统架构设计论文

disstertation 软考高级-系统架构设计师-论文&#xff1a;论文范围&#xff08;十大知识领域&#xff09;、历年论题、预测论题及论述过程、论文要点、论文模板等。 —— 2025 年 4 月 4 日 甲辰年三月初七 清明 目录 disstertation1、论文范围&#xff08;十大核心领域&#x…

数学复习笔记 26

5.25&#xff1a;这题还是有点难度的。主要是出现了新的知识点&#xff0c;我现在还没有那么熟悉这个新的知识点。这块就是&#xff0c;假设一个矩阵可以写成一个列向量乘以一个行向量的形式&#xff0c;这两个向量都是非零向量&#xff0c;那么这个矩阵的秩等于一。这个的原理…

[Java 基础]注释

注释在编程中扮演着非常重要的角色&#xff0c;它们是写给人类阅读的&#xff0c;而不是给计算机执行的。良好的注释可以极大地提高代码的可读性和可维护性。 为什么需要注释&#xff1f; 提高可读性&#xff1a; 注释可以解释代码的功能、实现思路、特殊处理等&#xff0c;帮…