[week15] ZJM 与霍格沃兹 —— 字符串哈希

2023-05-16

文章目录

  • 题意
    • Input
    • Output
    • 输入样例
    • 输出样例
    • 提示
  • 分析
  • 总结
  • 代码

题意

ZJM 为了准备霍格沃兹的期末考试,决心背魔咒词典,一举拿下咒语翻译题
题库格式:[魔咒] 对应功能
背完题库后,ZJM 开始刷题,现共有 N 道题,每道题给出一个字符串,可能是 [魔咒],也可能是对应功能
ZJM 需要识别这个题目给出的是 [魔咒] 还是对应功能,并写出转换的结果,如果在魔咒词典里找不到,输出 “what?”

Input

首先列出魔咒词典中不超过100000条不同的咒语,每条格式为:

[魔咒] 对应功能

其中“魔咒”和“对应功能”分别为长度不超过20和80的字符串,字符串中保证不包含字符“[”和“]”,且“]”和后面的字符串之间有且仅有一个空格。魔咒词典最后一行以“@END@”结束,这一行不属于词典中的词条。
词典之后的一行包含正整数N(<=1000),随后是N个测试用例。每个测试用例占一行,或者给出“[魔咒]”,或者给出“对应功能”。

Output

每个测试用例的输出占一行,输出魔咒对应的功能,或者功能对应的魔咒。如果在词典中查不到,就输出“what?”

输入样例

[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

输出样例

light the wand
accio
what?
what?

提示


分析

这是一道利用字符串哈希解决的经典问题。


  • 字符串哈希

1. 什么是字符串哈希?

字符串哈希指的就是将一个字符串转换为一个值进行处理的方法。

公式如下:

一个长度为n的字符串,

hash =(字符1值 * seed^n + 字符2值 * seed^(n-1) ... + 字符n值 * seed^1)% mod

  • 字符值可以有多种规定方式:

    1)如都是由大写字母或小写字母组成的字符串,则可以用字母顺序来作为值。如a = 1,b = 2…
    2)如除字母外包含其他多种字符,可以用ascii码作为值。

  • seed取值
    seed常见的取值为7、17、131

  • 取余处理
    取余处理是为了保证不会溢出造成结果错误。
    1)mod取1e9+7
    2)不需要mod,而是将数据类型换做unsigned long long,利用该数据类型的自然溢出处理取余。

2. 多种情况的字符串哈希计算

除去给出一个字符串求哈希值以外,我们还有可能遇到将两个字符串合并或者原字符串中某些字符发生变动的情况。而在这两种情况下,同样可以求出新字符串的哈希值。

  • 字符串中某些字符发生变动

一个易懂的小🌰:
在这里插入图片描述
原字符串的哈希值 - 被替换字符x的值 * seedi, 即为去掉字符x后的字符串哈希值。而再加上替换字符y的值 * seedi ,就是去掉原字符后的字符串加上新字符的字符串哈希值。

  • 合并两个字符串
    在这里插入图片描述

其实这个也很好理解。在新字符串中字符串1在前半部分,字符串2在后半部分,若对这个新字符串进行哈希计算会发现,字符串1 中所有字符对应所乘的seed的幂将会增加len2(字符串2的长度)。这是因为字符串1中的每个字符所在的字符串的长度增加了len2,因此幂要从len2+len1开始递减,而原本是从len1。

因此将字符串1的哈希值乘以seedlen2再加上字符串2的哈希值,再求模即为合并后的字符串哈希值。

3. 注意事项

利用哈希问题求解值得注意的有几点:

  • 在写代码的过程中不能完全按照公式来计算。因为在求解的过程中,在对总和求余之前计算的每一部分都可能溢出,因此在计算的每一部分都要作防止溢出的处理。
  • 其实很容易想到,可能存在不同的字符串有相同的哈希值。当遇到这种情况的时候,需要改变seed的取值进行计算。但是也存在一种无论取什么seed都会发生冲突的情况,那么此时就不能选择字符串哈希解决问题。

4. 适合的问题类型

字符串哈希值非常适合快速比较和字符串之间的映射。

  • 可以通过比较两个字符串的哈希值来确定其是否相等
  • 可以通过map利用字符串哈希值实现两个字符串之间的映射
  • 同样由于字符串哈希的不可逆性(也就是无法通过哈希值还原字符串),这种做法可以广泛运用于密码学

  • 题目分析

根据题目可以发现,我们需要根据题目给出的数据建立咒语到功能的相互映射。因此显然这就是一道需要字符串哈希解决的问题。

那么为什么不能直接建立字符串到字符串的映射呢?是因为根据题目要求需要建立双向映射,如果直接存储字符串就意味着需要将每个字符串存储两次,这种做法会导致超容。

因此我们需要将每个字符串的存储次数减小到一次。那么就可以用map分别建立咒语字符串哈希值到对应功能在数组中的下标以及功能字符串哈希值到对应咒语在数组中的下标。

首先判断题目给出的查询数据是咒语还是功能,然后将查询字符串求哈希值,查找该哈希值在对应的map中是否存在。若不存在说明没有该咒语或功能,若存在则从对应数组中取出其映射下标位置的字符串。


  • 问题

这道题目主要的处理都是对于字符和字符串,因此对输入数据的细节十分重要。

  • 题目并没有明确规定只有字母,因此此处求哈希值时每个字符值选用ascii码。
  • 输入数据中咒语和功能之间存在一个空格。如果不处理这个空格,利用getline输入功能字符串后,功能字符串将存在一个多余的空格。输入数据中在输入n(查询次数)后有一个提行符,如果不处理同样可能会出现问题,因此也要用getchar处理。
  • 在调试的过程中还遇到了一个玄学的问题。
    这样的写法就会出现错误:
        spell[trans(s2)] = tot;         //用功能哈希值映射咒语下标
        functions[trans(s1)] = tot;     //用咒语哈希值映射功能下标
        spell2[tot++] = s1;               //将咒语和功能存储起来
        func2[tot++] = s2;

但是,改变一下顺序后的写法就是正确的:

		spell2[tot] = s1;               //将咒语和功能存储起来
        func2[tot] = s2;
        spell[trans(s2)] = tot;         //用功能哈希值映射咒语下标
        functions[trans(s1)] = tot;     //用咒语哈希值映射功能下标
        tot++;

总结

  1. 数组和map容器取名字真的是个技术活,不然写到一半把自己都能给绕晕
  2. 经常调试成功的做法都很玄学,不明所以然👋

代码

//
//
//  main.cpp
//  lab1
//
//

#include <string>
#include <map>
#include <string.h>
#include <memory.h>
#include <iostream>
using namespace std;

//从功能的字符串哈希值映射到对应咒语下标
//从咒语的字符串哈希值映射到对应功能下标
map<unsigned long long,int> spell,functions;
string spell2[100001],func2[100001];        //存储咒语、功能
unsigned long long t = 7;

unsigned long long trans(string s)          //将字符串转换为值
{
    unsigned long long ans = 0,seed = t;
    
    
    for(int i = s.size() - 1 ; i >= 0 ; i-- )
    {

        ans += (unsigned long long)s[i] * seed;
        
        seed *= t;
    }
        
    return ans;
}

int main()
{
    ios::sync_with_stdio(false);
    
    string s1,s2,s;
    int tot = 0;
    
    while( cin>>s1 )
    {
        if( s1 == "@END@" )
            break;
        
        getchar();          //把咒语和功能之间的空格吃掉
        getline(cin,s2);
        
        s1.erase(0, 1);                 //删除咒语首尾的[]
        s1.erase(s1.size() - 1,1);
       
       
        spell2[tot] = s1;               //将咒语和功能存储起来
        func2[tot] = s2;
        spell[trans(s2)] = tot;         //用功能哈希值映射咒语下标
        functions[trans(s1)] = tot;     //用咒语哈希值映射功能下标
        tot++;

    }
    
    int n = 0;
    cin>>n;
    getchar();          //吃掉n之后的提行符
    
    for( int i = 0 ; i < n ; i++ )
    {
        getline(cin,s);
        
        if( s[0] == '[' && s[s.size() - 1] == ']' )     //若输入的是咒语
        {
            s.erase(0, 1);
            s.erase(s.size() - 1,1);
  
            auto it = functions.begin();            //查看该咒语的哈希值是否存在
            it = functions.find(trans(s));
            
            if( it != functions.end() )             //存在则输出对应功能
                cout<<func2[it->second]<<endl;
            else
                cout<<"what?"<<endl;
            
            
        }
        else
        {
            auto it = spell.begin();                //查看该功能哈希值是否存在
            it = spell.find(trans(s));
            
            if( it != spell.end() )                 //存在则输出对应咒语
                cout<<spell2[it->second]<<endl;
            else
                cout<<"what?"<<endl;
            
        }
    }
    
    return 0;
}

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

[week15] ZJM 与霍格沃兹 —— 字符串哈希 的相关文章

随机推荐

  • Ubuntu 20.04 安装 tensorflow-gpu

    1 安装Anaconda3 1 1 下载安装包 wget P tmp https repo anaconda com archive Anaconda3 2020 02 Linux x86 64 sh 1 2 安装 bash tmp Ana
  • 实验3  数据库综合查询

    实验3 数据库综合查询 一 实验目的 掌握SELECT语句的基本语法和查询条件表示方法 xff1b 掌握查询条件种类和表示方法 xff1b 掌握连接查询的表示及使用 xff1b 掌握嵌套查询的表示及使用 xff1b 了解集合查询的表示及使用
  • Ubuntu18安装mysql8.0

    一 删除mysql 5 7 卸载 sudo apt get remove mysql common sudo apt get autoremove purge mysql server 5 7 清理残留数据 dpkg l grep rc a
  • 将arduino uno的数据上传到云平台

    文章目录 将arduino uno的数据上传到云平台解决方案adruino uno方面代码esp8266 方面代码主函数阿里云sdkcpp部分函数头部分 将arduino uno的数据上传到云平台 解决方案 加一块esp8266的单片机 x
  • 华为IS-IS基础配置

    目录 一 原理概述 二 实验要求 三 实验拓扑 四 实验步骤 一 原理概述 1 IS IS xff1a Intermediate System to Intermediate System xff0c 中间系统到中间系统 2 链路状态协议
  • 基于markdown-it打造的markdown编辑器

    前言 markdown it是一个用来解析markdown的库 xff0c 它可以将markdown编译为html xff0c 然后解析时markdown it会根据规则生成tokens xff0c 如果需要自定义 xff0c 就通过rul
  • WiFi模块ESP-07s开发过程(学习笔记)

    目录 注意事项获取AT指令用到的指令通过返回的指令提取自己想要的信息 注意事项 转义字符 xff1a xff1a C中定义了一些字母前加 34 34 来表示常见的那些不能显示的ASCII字符 xff0c 如 0 t n等 xff0c 就称为
  • Vue3 table表格使用axios调用后端Api数据,统一返回格式

    1 安装axios npm install axios 2 封装axios span class token keyword import span span class token namespace axios span span cl
  • 关于C++的string字符串拼接问题(和“字符转字符串”问题有关)

    xff08 只有气到我肺都炸了的情况下我才可能废一些时间去写博客 xff08 主要是写一些气话 xff09 xff0c 但现在气消得差不多了我也骂不出什么话了 正文 1 字符串拼接分软拼接和硬拼接 xff08 软硬拼接 是我自己发明的词 实
  • [week2]化学——识别烷烃基

    文章目录 题意InputOutput输入样例输出样例 分析总结代码 题意 化学很神奇 xff0c 以下是烷烃基 假设如上图 xff0c 这个烷烃基有6个原子和5个化学键 xff0c 6个原子分别标号1 6 xff0c 然后用一对数字 a b
  • [week2]模拟OJ成绩排名系统(简易版)

    文章目录 题意InputOutput输入样例输出样例 分析总结代码 题意 题面宛如小作文233 程序设计思维作业和实验使用的实时评测系统 xff0c 具有及时获得成绩排名的特点 xff0c 那它的功能是怎么实现的呢 xff1f 我们千辛万苦
  • [week3]区间选点问题——贪心算法

    目录 题意InputOutput输入样例输出样例 分析总结代码 题意 数轴上有 n 个闭区间 a i b i 取尽量少的点 xff0c 使得每个区间内都至少有一个点 xff08 不同区间内含的点可以是同一个 xff09 Input 第一行1
  • [week3]区间覆盖问题——贪心算法

    目录 题意InputOutput输入样例输出样例提示 分析总结代码 题意 数轴上有 n 1 lt 61 n lt 61 25000 个闭区间 ai bi xff0c 选择尽量少的区间覆盖一条指定线段 1 t xff08 1 lt 61 t
  • [csp模拟1]咕咕东的奇遇——(一)

    目录 题意InputOutput输入样例输出样例提示 分析总结代码 题意 咕咕东是个贪玩的孩子 xff0c 有一天 xff0c 他从上古遗迹中得到了一个神奇的圆环 这个圆环由字母表组成首尾相接的环 xff0c 环上有一个指针 xff0c 最
  • Linux挂载镜像的一些命令

    Linux挂载镜像的一些命令 在Linux中 xff0c 可以用losetup命令来设置无分区空白镜像到loop设备上 xff0c 用kpartx 来kpartx映射分区的镜像到loop设备上 之后通过mount命令将loop设备与系统文件
  • [week5]平衡字符串——尺取法

    目录 题意InputOutput输入样例输出样例提示 分析总结代码 题意 一个长度为 n 的字符串 s xff0c 其中仅包含 Q W E R 四种字符 如果四种字符在字符串中出现次数均为 n 4 xff0c 则其为一个平衡字符串 现可以将
  • [csp模拟2]T4——咕咕东的奇妙序列

    文章目录 题意InputOutput输入样例输出样例提示 分析总结代码 题意 咕咕东 正在上可怕的复变函数 xff0c 但对于稳拿A Plus的 咕咕东 来说 xff0c 她早已不再听课 xff0c 此时她在睡梦中 突然想到了一个奇怪的无限
  • [week9]签到题(长凳)——贪心算法

    文章目录 题意InputOutput输入样例输出样例提示 分析总结代码 题意 SDUQD 旁边的滨海公园有 x 条长凳 第 i 个长凳上坐着 a i 个人 这时候又有 y 个人将来到公园 xff0c 他们将选择坐在某些公园中的长凳上 xff
  • [week14] Q老师与十字叉

    文章目录 题意InputOutput输入样例输出样例提示 分析总结代码 题意 Q老师 得到一张 n 行 m 列的网格图 xff0c 上面每一个格子要么是白色的要么是黑色的 Q老师认为失去了 十字叉 的网格图莫得灵魂 一个十字叉可以用一个数对
  • [week15] ZJM 与霍格沃兹 —— 字符串哈希

    文章目录 题意InputOutput输入样例输出样例提示 分析总结代码 题意 ZJM 为了准备霍格沃兹的期末考试 xff0c 决心背魔咒词典 xff0c 一举拿下咒语翻译题 题库格式 xff1a 魔咒 对应功能 背完题库后 xff0c ZJ