[哈希/字典树/kmp]Exercise Week15 A~C
目录
- A.[Hash]咒语
- 题意
- 样例
- 样例输入:
- 样例输出:
- 思路
- 总结
- 代码
- B.[字典树]生日礼物
- 题意
- 样例
- 样例输入:
- 样例输出:
- 思路
- 总结
- 代码
- C.[kmp]纸条
- 题意
- 样例
- 样例输入:
- 样例输出:
- 思路
- 总结
- 代码
A.[Hash]咒语
题意
ZJM 为了准备霍格沃兹的期末考试,决心背魔咒词典,一举拿下咒语翻译题
题库格式:[魔咒] 对应功能
背完题库后,ZJM 开始刷题,现共有 N 道题,每道题给出一个字符串,可能是 [魔咒],也可能是对应功能
ZJM 需要识别这个题目给出的是 [魔咒] 还是对应功能,并写出转换的结果,如果在魔咒词典里找不到,输出 “what?”
样例
样例输入:
首先列出魔咒词典中不超过100000条不同的咒语,每条格式为:
[魔咒] 对应功能
其中“魔咒”和“对应功能”分别为长度不超过20和80的字符串,字符串中保证不包含字符“[”和“]”,且“]”和后面的字符串之间有且仅有一个空格。魔咒词典最后一行以“@END@”结束,这一行不属于词典中的词条。
词典之后的一行包含正整数N(<=1000),随后是N个测试用例。每个测试用例占一行,或者给出“[魔咒]”,或者给出“对应功能”。
[expelliarmus] the disarming charm
[rictusempra] send a jet of silver light to hit the enemy
[tarantallegra] control the movement of one's legs
[serpensortia] shoot a snake out of the end of one's wand
[lumos] light the wand
[obliviate] the memory charm
[expecto patronum] send a Patronus to the dementors
[accio] the summoning charm
@END@
4
[lumos]
the summoning charm
[arha]
take me to the sky
样例输出:
每个测试用例的输出占一行,输出魔咒对应的功能,或者功能对应的魔咒。如果在词典中查不到,就输出“what?”
light the wand
accio
what?
what?
思路
1.字符串哈希 用两个map进行映射
map[Hash1] = index,s1[index] = 翻译
map[Hash2] = index,s2[index] = 英文
2.对于输入的每一次查询 首先判断是咒语还是翻译
然后再在对应的 map 中查询即可
PS:因为可能出现其他字符 故要注意减 ’ ’ 而不是减’a’ 因为用到了unsigned long long 自然溢出 故加的值不能为负值
总结
一个经典的字符串哈希问题,可以让我们很好的打下哈希算法的基础
seed:通常取7、17、131
mod:1e9+7 或 unsigned long long自然溢出
可以在O(1)时间内修改,合并
代码
#include<iostream>
#include<string.h>
#include<algorithm>
#include<math.h>
#include<stdio.h>
#include<map>
#define MAXN 100010
#define seed 131
#define ull unsigned long long
using namespace std;
char mz[MAXN][30],fy[MAXN][90];
int tnt,n;
map<ull,int> M,F;
ull Hash(char *str)
{ull sum=0,sed=1;for(int i=strlen(str);i>=0;i--){sed*=seed;sum+=(str[i]-' ')*sed; }return sum;
}
char q[110];
int main()
{string s1,s2;while(true){cin>>s1;if(s1.compare("@END@")==0) break;tnt++;getline(cin,s2);strcpy(mz[tnt],s1.c_str());strcpy(fy[tnt],s2.c_str()+1);M[Hash(mz[tnt])]=tnt;F[Hash(fy[tnt])]=tnt;}cin>>n;getchar();string s3;for(int i=1;i<=n;i++){getline(cin,s3);strcpy(q,s3.c_str());ull has=Hash(q);if(q[0]=='[')//å’’è¯{if(M.find(has)==M.end()) cout<<"what?"<<endl;else cout<<fy[M[has]]<<endl;}else{if(F.find(has)==F.end()) cout<<"what?"<<endl;else {for(int i=1;i<strlen(mz[F[has]])-1;i++)cout<<mz[F[has]][i];cout<<endl;}}}return 0;
}
B.[字典树]生日礼物
题意
ZJM 收到了 Q老师 送来的生日礼物,但是被 Q老师 加密了。只有 ZJM 能够回答对 Q老师 的问题,Q老师 才会把密码告诉 ZJM。
Q老师 给了 ZJM 一些仅有 01 组成的二进制编码串, 他问 ZJM:是否存在一个串是另一个串的前缀.
样例
样例输入:
多组数据。每组数据中包含多个仅有01组成的字符串,以一个9作为该组数据结束的标志。
01
10
0010
0000
9
01
10
010
0000
9
样例输出:
对于第 k 组数据(从1开始标号),如果不存在一个字符串使另一个的前缀,输出"Set k is immediately decodable",否则输出"Set k is not immediately decodable"。
每组数据的输出单独一行
Set 1 is immediately decodable
Set 2 is not immediately decodable
思路
1.由于是单个字符串与一堆字符串之间的匹配,我们首先想到字典树
2.如何判断是否存在一个字符串是其他某个字符串的子串?
我们要考虑两方面,
一是,某字符串是否是其他字符串的前缀?
二是,其他字符串中是否存在某一字符串,是该字符串的前缀?
3.故对于每一字符串,我们可以边插入到字符串中,边判断即可
总结
我们通常用一个结构体来存储字典树
基本函数有clear(),insert(),query()(查询字典树中是否有某字符串的前缀)
代码
#include<iostream>
#include<string.h>
#include<algorithm>
#include<math.h>
#include<stdio.h>
#include<map>
using namespace std;
struct Trie
{//N为字典树的最多节点个数 charset为字符的种类数 本题中只有0和1static const int N=100010,charset=2;//child[now][x] 表示now的第x个儿子 //flag[now]=1表示now是某一字符串的结尾int tnt,root,child[N][charset],flag[N];Trie() {memset(child,-1,sizeof(child));memset(flag,0,sizeof(flag));root=tnt=0;}void clear(){memset(child,-1,sizeof(child));memset(flag,0,sizeof(flag));root=tnt=0;}/*void insert(char *str){//原版insertint now=root;for(int i=0;i<strlen(str);i++){int x=str-'0';//if(child[now][x]==-1)//如果还没有创建该节点{child[now][x]=++tnt;//创建新节点flag[now]=0;}now=child[now][x];}flag[now]=1;//标识结尾}*/int insert(char *str){int now=root,len=strlen(str),ok=0;for(int i=0;i<len;i++){int x=str[i]-'0';if(child[now][x]==-1){child[now][x]=++tnt;flag[now]=0;}else if(i==len-1||flag[child[now][x]]) ok=1;//i==len-1 表示 当前子串是之前曾经插入过的字符串的子串//flag[child[now][x]] 表示 之前的字符串是当前插入的字符串的子串now=child[now][x];}flag[now]=1;return ok;}bool query(char * str){int now=root;for(int i=0;i<strlen(str);i++){int x=str[i]-'0';if(child[now][x]==-1) return false;//还没有找到尾就到头了if(flag[now]) return true;//已经找到了一个字符子串now=child[now][x];}return false;//到头了还是没找到一个子串}
};
int T;
char c[1010];
int main()
{Trie t;string s;bool ans=false;while(cin>>s){if(s.compare("9")==0) {T++;if(!ans) cout<<"Set "<<T<<" is immediately decodable"<<endl;else cout<<"Set "<<T<<" is not immediately decodable"<<endl;t.clear();ans=false;continue;}strcpy(c,s.c_str());if(t.insert(c)) ans=true;}system("pause");return 0;
}
C.[kmp]纸条
题意
ZJM 的女朋友是一个书法家,喜欢写一些好看的英文书法。有一天 ZJM 拿到了她写的纸条,纸条上的字暗示了 ZJM 的女朋友 想给 ZJM 送生日礼物。ZJM 想知道自己收到的礼物是不是就是她送的,于是想看看自己收到的礼物在纸条中出现了多少次。
样例
样例输入:
第一行输入一个整数代表数据的组数
每组数据第一行一个字符串 P 代表 ZJM 想要的礼物, 包含英语字符 {‘A’, ‘B’, ‘C’, …, ‘Z’}, 并且字符串长度满足 1 ≤ |P| ≤ 10,000 (|P| 代表字符串 P 的长度).
接下来一行一个字符串 S 代表 ZJM 女朋友的纸条, 也包含英语字符 {‘A’, ‘B’, ‘C’, …, ‘Z’}, 满足 |P| ≤ |S| ≤ 1,000,000.
3
BAPC
BAPC
AZA
AZAZAZA
VERDI
AVERDXIVYERDIAN
样例输出:
输出一行 一个整数代表 P 在 S中出现的次数.
1
3
0
思路
1.由于本题为单个字符串与单个字符串匹配,是典型的查询S在T中出现的次数的问题,故可以用KMP算法在O(m+n)内实现
2.KMP的模板题,只需在匹配到时将ans++即可
KMP有两部分难点
一是Next[]数组的快速求解
二是KMP算法中的匹配过程
详情可见:KMP算法详细讲解
总结
代码
#include<iostream>
#include<string>
#include<algorithm>
#include<math.h>
#include<stdio.h>
#include<map>
using namespace std;
int n,ans;
int Next[1000010];
string P,S;
void get_next()
{Next[0]=0;for(int i=1,j=0;i<P.length();i++){while(j&&P[j]!=P[i]) j=Next[j-1];if(P[j]==P[i]) j++;Next[i]=j;}
}
void kmp()
{int len2=S.length();int j=0;//当前匹配到了P的第几个字符get_next();for(int i=0;i<len2;i++){//只有当j!=0时 向前寻找才有意义while(j&&P[j]!=S[i]) j=Next[j-1];if(P[j]==S[i]) j++;if(j==P.length())//匹配到了一次{ans++;j=Next[j-1];}}
}
int main()
{cin>>n;while(n--){memset(Next,0,sizeof(Next));ans=0;cin>>P>>S;kmp();cout<<ans<<endl;}return 0;
}
[哈希/字典树/kmp]Exercise Week15 A~C相关推荐
- 【Hihocoder - offer编程练习赛39 - D】前缀后缀查询(后缀字典树,哈希,思维)
题干: 时间限制:10000ms 单点时限:1000ms 内存限制:512MB 描述 给定一个包含N个单词的字典:{W1, W2, W3, ... WN},其中第i个单词Wi有具有一个权值Vi. 现在 ...
- 012-数据结构-树形结构-哈希树[hashtree]、字典树[trietree]、后缀树
一.哈希树概述 1.1..其他树背景 二叉排序树,平衡二叉树,红黑树等二叉排序树.在大数据量时树高很深,我们不断向下找寻值时会比较很多次.二叉排序树自身是有顺序结构的,每个结点除最小结点和最大结点外都 ...
- 2020.9.9华为笔试记忆:KMP+记忆化搜索+字典树
2020.9.9华为笔试 当然,出现在我博客中的笔试都不是我自己的笔试(人家也不给我发笔试链接,小声bibi,诶,好像我也没投,hhhahahha 记者:为什么要做笔试? 我:生活无聊了喏,肯定要做啊 ...
- 基础数据结构(二):字典树、并查集、堆、哈希表、字符串的哈希方式、STL的常见容器及其接口
文章目录 一.字典树Trie 1 原理 2 Trie字符串统计 3 [LeetCode 208. 实现 Trie (前缀树)](https://leetcode-cn.com/problems/imp ...
- [leetcode 面试题 17.17] -- 多次搜索,KMP与字典树
[leetcode 面试题 17.17] -- 多次搜索 题目来源 分析 KMP思路 完整代码 字典树 完整代码 题目来源 https://leetcode-cn.com/problems/multi ...
- LeetCode第 57 场力扣夜喵双周赛(差分数组、单调栈) and 第 251 场力扣周赛(状态压缩动规,树的序列化,树哈希,字典树)
LeetCode第 57 场力扣夜喵双周赛 离knight勋章越来越近,不过水平没有丝毫涨进 1941. 检查是否所有字符出现次数相同 题目描述 给你一个字符串 s ,如果 s 是一个 好 字符串,请 ...
- [week15] B - ZJM与生日礼物(选做)—— 字典树
文章目录 题意 Input Output 输入样例 输出样例 提示 分析 总结 代码 题意 ZJM 收到了 Q老师 送来的生日礼物,但是被 Q老师 加密了.只有 ZJM 能够回答对 Q老师 的问题,Q ...
- 【Week15作业 B】ZJM与生日礼物【字典树】
题意: ZJM 收到了 Q老师 送来的生日礼物,但是被 Q老师 加密了.只有 ZJM 能够回答对 Q老师 的问题,Q老师 才会把密码告诉 ZJM. Q老师 给了 ZJM 一些仅有 01 组成的二进制编 ...
- Week15—字典树应用,字符串包含问题
问题描述 ZJM 收到了 Q老师 送来的生日礼物,但是被 Q老师 加密了.只有 ZJM 能够回答对 Q老师 的问题,Q老师 才会把密码告诉 ZJM. Q老师 给了 ZJM 一些仅有 01 组成的二进制 ...
- 0x16.基本数据结构 — Trie树(字典树)+ A C 自 动 机
目录 用TrieTrieTrie树来处理整数异或问题是真的舒服! 一.TrieTrieTrie树 TrieTrieTrie的基本操作 0.初始化 1.插入 2.检索 二.TrieTrieTrie树例题 ...
最新文章
- Elastic-Job中的ScriptJob
- 【分享】虹软人脸识别应用开发过程
- Spring Boot 与消息 (JMS、AMQP、RabbitMQ)
- IOC操作Bean管理XML方式(FactoryBean)
- mac下安装caffe
- my footprint :走过的路
- Android中样式及主题
- android input 点击事件失效,React Native:TextInput元素上的onContentSizeChange事件在Android上不起作用...
- 一种新的人机交流方式——sound ware 声件
- Git:git commit后撤销commit 提交
- 软媒时间---任务栏滚动工具
- 百科不全书之Python常用库
- 一文聊透对象在JVM中的内存布局,以及内存对齐和压缩指针的原理及应用
- Couldnt check the working tree for unmerged files because of an error. bad signature index file cor
- 数据校验(身份证,ip地址,银行卡号等)
- 程序猿最后的愿望是什么?
- WinForm,可能是Windows上手最快的图形框架了
- php 微信永久登录,php微信登录
- IPv4协议中的UDP分片问题
- 小路绫只会做料理 (ayaya)(树状数组 二分)
热门文章
- 实用开源镜像站(将持续补全......)
- wps压缩word文档方法
- 利用Python进行数据分析的学习笔记——chap12
- scrapy 使用无忧代理IP 需要填写无忧代理IP提供的API订单号(请到用户中心获取) 这个是要钱吗??...
- matlab 中输入log就是ln吗?(ln就是log以e为底的对数)
- (OK) 国内常用NTP服务器地址及IP
- 破解docx文档保护密码
- DS18B20数字温度计 (二) 测温, ROM和CRC算法
- 未来是否繁花似锦,源自我们当下之努力
- 2020年中国不支持苹果_苹果2020年9月事件提示