当前位置: 首页 > article >正文

【例题2】图书管理(信息学奥赛一本通- P1456)

【题目描述】图书管理是一件十分繁杂的工作在一个图书馆中每天都会有许多新书加入。为了更方便的管理图书以便于帮助想要借书的客人快速查找他们是否有他们所需要的书我们需要设计一个图书查找系统。该系统需要支持 2 种操作add(s) 表示新加入一本书名为 s 的图书。find(s) 表示查询是否存在一本书名为 s 的图书。【输入】第一行包括一个正整数 n表示操作数。 以下 n 行每行给出 2 种操作中的某一个指令条指令格式为add s find s在书名 s 与指令addfind之间有一个隔开我们保证所有书名的长度都不超过 200。可以假设读入数据是准确无误的。【输出】对于每个 find(s) 指令我们必须对应的输出一行 yes 或 no表示当前所查询的书是否存在于图书馆内。注意一开始时图书馆内是没有一本图书的。并且对于相同字母不同大小写的书名我们认为它们是不同的。【输入样例】4 add Inside C# find Effective Java add Effective Java find Effective Java【输出样例】no yes【提示】数据范围n≤30000。今天和大家分享一道经典的字符串查找题目——图书查找系统。这道题表面上只是简单的“存书”和“找书”但如果你只是无脑开一个大数组每次find都把数组从头到尾扫一遍遇到稍微严格一点的评测机绝对会被卡成超时。在解决这道题的过程中我展示了代码的三次“进化”下面把整个思考过程、三版代码的演进以及避坑指南整理出来。一、 题目分析核心需求实现两个操作add添加书名和find查找书名是否存在。数据范围操作数N≤30000书名长度≤200。大小写敏感带空格。痛点如果用普通的string数组存储每次find操作的最坏时间复杂度是O(K×L)K为已存书的数量L为字符串长度。如果有一半是add一半是find运算次数会飙升到 15000×15000×200肯定会超时。我们需要一个近乎O(1)的快速查找方案。二、 代码的进化过程进化阶段一普通数组手写字符串哈希 (V1)既然直接比较长字符串太慢第一反应是把字符串压缩成数字。利用unsigned long long(ull) 自动溢出取模的特性用131进制把长达200个字符的书名变成一个巨大的整数存进数组里。虽然比较数字比比较字符串快但查找时依然需要写个for(int i1; icnt; i)遍历数组。治标不治本虽然这道题能提交通过但最坏复杂度还是 O(N^2)在边缘疯狂试探。V1代码实现//数组哈希 #include iostream #include cstring using namespace std; typedef unsigned long long ull; int n; string func;//代表是何种操作 ull ans1[30010];//记录每个添加的图书的哈希值 int cnt0;//总共添加书籍数 int main(){ ios::sync_with_stdio(false); cin.tie(0); cinn; while(n--){ cinfunc; cin.get();//吃掉操作符后面的空格 //增加操作 if(func[0]a){ cnt; string s; getline(cin,s); //算出当前添加这本书的哈希值并存入数组ans1 for(int i0;is.size();i) ans1[cnt]ans1[cnt]*131s[i]; } else if(func[0]f){ bool flag0; string s; getline(cin,s); ull ans20; for(int i0;is.size();i) ans2ans2*131s[i]; //问题依然需要从头到尾扫一遍数组 for(int i1;icnt;i){ if(ans2ans1[i]){ flag1; coutyes\n; break; } } if(flag0) coutno\n; } } return 0; }进化阶段二STL 哈希表 手写哈希 (V2)既然瓶颈在“遍历查找”上直接祭出O(1)查找神器unordered_set。我们建一个unordered_setull每次add时先手动把字符串用131进制算出哈希数字丢进set里find时也算出数字直接调用.count()判断。优势速度直接起飞。时间复杂度被死死压在了O(N×L)。这也是在高级算法竞赛中为了防止出题人针对STL底层哈希进行“卡常构造哈希冲突数据”的标准硬核写法。V2代码实现//哈希表加哈希优化 //数组哈希 #include iostream #include cstring #include unordered_set//哈希表 using namespace std; typedef unsigned long long ull; int n; unordered_setull ans3;//存放已有的图书的哈希值的哈希表 string func;//代表是何种操作 int main(){ ios::sync_with_stdio(false); cin.tie(0); cinn; while(n--){ cinfunc; cin.get();//吃掉操作符后面的空格 //增加操作 if(func[0]a){ cnt; string s; getline(cin,s); ull ans10;//临时变量 存储这一次添加的书名的哈希值 for(int i0;is.size();i) ans1ans1*131s[i]; ans3.insert(ans1); } else if(func[0]f){ string s; getline(cin,s); ull ans20;//临时变量 存储这一次要查询的书名的哈希值 for(int i0;is.size();i) ans2ans2*131s[i]; //如果ans2当前已经存在哈希表中 输出yes if(ans3.count(ans2)) coutyes\n; //不存在 输出no else coutno\n; } } return 0; }进化阶段三纯血STL原生哈希 (V3)写完 V2 后转念一想这题毕竟是个纯应用题。C的unordered_set底层其实自带了工业级的字符串哈希函数如 MurmurHash或FNV-1a。 既然标准库自己能搞定而且分布极度均匀干嘛还要苦哈哈地写for循环去乘131呢直接把容器类型改成unordered_setstring把字符串原封不动地丢进去就行了。但是比赛还是不建议这么写竞赛时容易针对哈希表自带字符串哈希函数构造测试点从而卡掉你优势代码极短心智负担几乎为零是最标准的工程开发写法。V3代码实现//使用哈希表自带的字符串哈希函数 //不建议这么写还是建议自己写哈希函数因为竞赛时容易针对 //哈希表自带字符串哈希函数构造测试点从而卡掉你 //哈希表加哈希优化 //数组哈希 #include iostream #include cstring #include unordered_set//哈希表 直接存字符串 自动算哈希 using namespace std; int n; unordered_setstring ans;//存放已有的图书的哈希值的哈希表 string func;//代表是何种操作 int main(){ ios::sync_with_stdio(false); cin.tie(0); cinn; while(n--){ cinfunc; cin.get();//吃掉操作符后面的空格 //增加操作 if(func[0]a){ string s; getline(cin,s);//读取带有空格的整行书名 ans.insert(s); } else if(func[0]f){ string s; getline(cin,s); //如果字符串s当前已经存在哈希表中 输出yes if(ans.count(s)) coutyes\n; //不存在 输出no else coutno\n; } } return 0; }三、易错点点总结这道题逻辑虽然简单但藏着几个极其容易白给的C语法天坑极其致命的“流冲突”与残留空格题目输入格式是add 书名。必然会用到cinfunc;接着用getline(cin,s);。大坑cin不会吃掉它读完后面的那个空格/换行符。如果不做处理getline会直接把空格读进去导致后续所有书名前面都多了一个空格永远匹配不上。解法在两者之间必须加一个cin.get()精准备用地吃掉分隔符。ios::sync_with_stdio(false)的反噬加了流加速后千万不要用C语言的getchar()去吃空格。因为C和C的流已经解绑了混用会导致读入彻底错乱。老老实实用C的cin.get()。未初始化的局部变量在V1和V2中手动算哈希时如果在while内部写ull ans2;而不赋初值它会被分配一个内存残留的随机垃圾值。拿着垃圾值去乘131算出来的哈希全错。一定要写ull ans2 0;。写在最后从手算131进制加数组遍历到巧妙借用STLunordered_set虽然代码行数变少了但对底层内存排布、时间复杂度的认知要求却在逐步加深。能熟练把玩哈希表基本上就拿到了字符串查重问题的万能钥匙。

相关文章:

【例题2】图书管理(信息学奥赛一本通- P1456)

【题目描述】图书管理是一件十分繁杂的工作,在一个图书馆中每天都会有许多新书加入。为了更方便的管理图书(以便于帮助想要借书的客人快速查找他们是否有他们所需要的书),我们需要设计一个图书查找系统。该系统需要支持 2 种操作&…...

视频合并工具多合一版使用说明:批量合并视频/自定义命名/片头片尾/转场/硬件加速与并行转码

【视频合并工具多合一版】基于 FFmpeg 实现视频合并与转码,支持拖拽导入、排序、批量合并(按文件夹分组)、片头片尾、转场效果(含“保持原始时长”模式)、GPU 硬件加速(NVENC/QSV/AMF)、并行转码…...

告别语言障碍!Translumo:你的专属游戏外语翻译官

告别语言障碍!Translumo:你的专属游戏外语翻译官 【免费下载链接】Translumo Advanced real-time screen translator for games, hardcoded subtitles in videos, static text and etc. 项目地址: https://gitcode.com/gh_mirrors/tr/Translumo 还…...

Scroll Reverser:解决macOS多输入设备滚动冲突的终极方案

Scroll Reverser:解决macOS多输入设备滚动冲突的终极方案 【免费下载链接】Scroll-Reverser Per-device scrolling prefs on macOS. 项目地址: https://gitcode.com/gh_mirrors/sc/Scroll-Reverser 在macOS生态系统中,触控板与外接鼠标之间的滚动…...

鸿蒙Next实战:5分钟搞定跨应用拖拽图片功能(附完整代码)

鸿蒙Next实战:5分钟搞定跨应用拖拽图片功能(附完整代码) 在移动应用开发中,跨应用数据交互一直是提升用户体验的关键技术点。想象一下,用户无需繁琐的保存-导入流程,只需简单拖拽就能将图片从相册应用转移到…...

从新建工程到编译成功:一个完整Quartus II 18.0项目实战(含Verilog文件添加与管脚分配)

从零构建LED闪烁模块:Quartus II 18.0全流程开发指南 当你第一次打开Quartus II 18.0时,面对复杂的界面和众多选项可能会感到无从下手。本文将带你完成一个完整的LED闪烁模块开发流程——从创建工程到成功编译,通过这个具体项目理解每个操作的…...

Grafana仪表板安全嵌入实践:解决iframe跨域与登录验证难题

1. 为什么需要安全嵌入Grafana仪表板 在企业监控系统开发中,我们经常需要将Grafana仪表板集成到自有系统中。直接使用iframe嵌入看似简单,但实际操作时会遇到两个棘手问题:首先是浏览器控制台频繁报错"Refused to display in a frame&qu…...

张量与向量基础:AI 计算的数学本质

文章目录前言一、先搞懂:AI里天天说的向量,到底是个啥?1.1 别被数学定义吓住,向量就是"有序数字列表"1.2 用生活例子秒懂:向量就是"事物的数字化画像"1.3 向量的核心作用:让计算机能&q…...

软件测试认证2026:ROI最高的5个证书

在数字化转型加速的2026年,软件测试行业正经历深刻变革。随着AI自动化测试覆盖率突破60%、DevSecOps成为行业标配,企业对测试人才的需求已从单一技能转向体系化能力认证。认证不仅是职业跃迁的杠杆,更是投资回报率(ROI&#xff09…...

如何3分钟内免费获取全球气象数据?CDS API完整教程

如何3分钟内免费获取全球气象数据?CDS API完整教程 【免费下载链接】cdsapi Python API to access the Copernicus Climate Data Store (CDS) 项目地址: https://gitcode.com/gh_mirrors/cd/cdsapi 想象一下,你是一位气候研究员,需要…...

git 修改项目远程仓库地址

1. 查看当前远程仓库地址 git remote get-url origin 或 git remote -v2. 修改远程仓库地址 git remote set-url origin <新的远程仓库地址>3. 查看是否切换成功 git remote -v...

终极Windows快捷键冲突检测指南:Hotkey Detective深度解析

终极Windows快捷键冲突检测指南&#xff1a;Hotkey Detective深度解析 【免费下载链接】hotkey-detective A small program for investigating stolen key combinations under Windows 7 and later. 项目地址: https://gitcode.com/gh_mirrors/ho/hotkey-detective 你是…...

手把手教你为STM32F407添加USB2.0高速支持(含PHY选型与ULPI接线详解)

STM32F407 USB2.0高速通信实战指南&#xff1a;从PHY选型到性能优化 在嵌入式系统开发中&#xff0c;USB2.0高速接口&#xff08;480Mbps&#xff09;的实现一直是工程师面临的技术挑战之一。不同于USB1.1全速设备&#xff08;12Mbps&#xff09;&#xff0c;高速USB对信号完整…...

Go语言的Docker容器化实践

Go语言的Docker容器化实践 1. 容器化基础概念 1.1 Docker核心概念 镜像(Image)&#xff1a;应用程序及其依赖的打包容器(Container)&#xff1a;镜像的运行实例仓库(Repository)&#xff1a;存储镜像的地方 1.2 Go语言与Docker的优势 Go语言编译为静态二进制文件&#xff0c;体…...

DeOldify云原生部署:基于Docker和Kubernetes构建弹性伸缩服务

DeOldify云原生部署&#xff1a;基于Docker和Kubernetes构建弹性伸缩服务 1. 引言 想象一下&#xff0c;你手里有一批珍贵的老照片&#xff0c;它们承载着家族的记忆&#xff0c;但岁月留下的泛黄和模糊却让细节难以辨认。或者&#xff0c;你的内容创作团队需要为一部历史题材…...

Ansible 高并发实战:从异步到集群的完整方案

一、前言Ansible 高并发实战&#xff1a;从异步到集群的完整方案是 Java 后端开发中的核心知识点。本文覆盖Ansible、高并发、后端&#xff0c;配有完整可运行的代码示例。二、核心实现2.1 SpringBoot 项目结构// 标准 SpringBoot 控制器 RestController RequestMapping("…...

为什么你的AIAgent在压测中“静默崩溃”?揭秘LLM调用链中缺失的5层调试元数据

第一章&#xff1a;AIAgent架构监控与调试工具概览 2026奇点智能技术大会(https://ml-summit.org) AI Agent系统具备多层异构性——包含规划器&#xff08;Planner&#xff09;、记忆模块&#xff08;Memory&#xff09;、工具调用层&#xff08;Tool Router&#xff09;及执行…...

那些年,我们追过的技术潮流与踩过的“坑”

技术浪潮下的测试进化论在软件测试的十年激荡中&#xff0c;技术潮流如流星般划过天际——有的点亮前路&#xff0c;有的灼伤掌心。当自动化测试从“银弹神话”跌落神坛&#xff0c;当敏捷转型在流程夹缝中步履蹒跚&#xff0c;当AI测试的算法黑箱蒙上新的迷雾&#xff0c;测试…...

跟着AI学sql

1、左连接&#xff08;返回左表全部&#xff09; left join .. on ....表1 Person(PersonId,FirstName,LastName)表2 Address(AddressId,PersonId,City,State)查询每个人的姓、名、城市、州&#xff0c;没有人的地址也要显示select p.FirstName,p.LastName,a.City,a.Statefrom …...

前端动画新方法:别再用传统 CSS 动画了

前端动画新方法&#xff1a;别再用传统 CSS 动画了 什么是前端动画新方法&#xff1f; 前端动画新方法是指在前端开发中&#xff0c;随着技术的发展&#xff0c;出现的新的动画技术和方法。别以为动画只是简单的过渡效果&#xff0c;那是十年前的玩法了。 为什么需要关注前端动…...

驾校 AI 招生谁靠谱?懂驾培又懂 AI 才是关键

驾校 AI 招生谁靠谱&#xff1f;懂驾培又懂 AI 才是关键作者&#xff1a;安道利当下驾培行业&#xff0c;传统地推、硬广、老带新的招生效率持续下滑&#xff0c;获客成本飙升、线索转化率低迷&#xff0c;AI 招生已成为驾校破局的必选项。但市场上 AI 招生服务商鱼龙混杂&…...

SQL触发器在高并发下的可靠性设计_优化触发锁竞争范围

MySQL/PG触发器中应避免全表操作、非确定性函数及跨表更新&#xff0c;优先用NEW字段赋值、应用层传参、异步消息&#xff1b;须严格控制锁粒度并压测验证。触发器里别写 UPDATE 或 INSERT 全表操作高并发下最常见崩点&#xff1a;触发器里执行 UPDATE orders SET status proc…...

从面包板到PCB:我的第一个STC89C52RC学习板实战升级记录

从面包板到PCB&#xff1a;我的第一个STC89C52RC学习板实战升级记录 记得第一次在面包板上搭建STC89C52RC实验电路时&#xff0c;那些横七竖八的跳线就像一团理不清的毛线。每当需要修改电路&#xff0c;就得小心翼翼地拔出几根线&#xff0c;结果往往是牵一发而动全身——旁边…...

东莞PVC收缩膜源头厂家选择

在东莞&#xff0c;PVC 收缩膜的应用场景早已渗透五金、建材、日用品、电子等多个行业&#xff0c;成为企业包装的刚需材料。但面对市面上良莠不齐的源头厂家&#xff0c;如何精准筛选出 “靠谱、适配、有潜力” 的合作伙伴&#xff1f;今天&#xff0c;我们从 “发展规模、产品…...

从婴儿学步到AI进化:具身智能如何模仿人类学习过程?

从婴儿学步到AI进化&#xff1a;具身智能如何模仿人类学习过程&#xff1f; 在东京大学的一个实验室里&#xff0c;一台人形机器人正尝试用机械手指捏起桌上的积木。它失败了37次&#xff0c;却在第38次成功时将动作数据上传至云端——这个场景像极了人类婴儿第一次成功抓取玩具…...

HWSD2.0:从全球土壤数据到精准农业与生态评估的革新

1. HWSD2.0&#xff1a;土壤数据的革命性升级 记得十年前我第一次用HWSD1.2做农田土壤分析时&#xff0c;经常为数据精度不够发愁。那时候只有两层土壤数据&#xff0c;很多关键参数都缺失&#xff0c;做模型时不得不靠经验值来填补。现在HWSD2.0的发布&#xff0c;简直像给土壤…...

js 方法

数组转对象const foo document.querySelectorAll(.foo); const nodes Array.from(foo);立即执行函数可以写成箭头函数的形式。(() > { console.log(Welcome to the Internet.);})();const boundMethod (...params) > method.apply(this, params);function divide(a, …...

全文降AI工具价格效果对比:嘎嘎降AI、比话降AI怎么选

全文降AI工具价格效果对比&#xff1a;嘎嘎降AI、比话降AI怎么选 选全文降AI工具的时候&#xff0c;大家最关心两件事&#xff1a;一是效果好不好&#xff0c;二是价格贵不贵。 效果不好&#xff0c;花再少的钱也是浪费。效果好但价格离谱&#xff0c;很多同学也吃不消。所以最…...

全文降AI的好处:手动改 vs 工具全文降,省多少时间?

全文降AI的好处&#xff1a;手动改 vs 工具全文降&#xff0c;省多少时间&#xff1f; 说一个真实的场景。 论文初稿写完了&#xff0c;跑了一遍AI检测&#xff0c;结果55%。学校要求20%以下。你打开论文&#xff0c;开始逐段阅读检测报告里标红的段落&#xff0c;想着一段一段…...

全文降AI率对比实测:一次降完和分段降哪个效果更稳

全文降AI率对比实测&#xff1a;一次降完和分段降哪个效果更稳 有个问题一直困扰很多同学&#xff1a;降AI率的时候&#xff0c;是把整篇论文一次性丢进工具处理好&#xff0c;还是切成几段分别处理好&#xff1f; 直觉上似乎分段处理更"精细"&#xff0c;毕竟可以对…...