于是他错误的点名开始了
我发现有关hash得题目有些是可以通过map数组来完成的:何为map数组,我们先思考一下最简单的桶的排序,桶排序是将我们需要数字最为下标输进数组中,而数组是存放的数字是这个数字出现的次数,但是由于如果数据过大且数字并不稠密,则会导致浪费很多空间。而map数组也是桶排序一样的思想,我们首先来看map数组是怎样定义的?
map<string ,int>a;
string是字符串的意思,这个是将字符串作为下标,后面的int就是map数组所存的数字,一般运用于这个字符串出现了几次。看看这个思路是不是和桶排序差不多。这个map在#include<map>这个头文件中
好既然我们知道了如何使用map,那我们就压迫思考如何使用map数组来解决这一道题目
思路如下:我们将每一个字符串作为map数组的下标,如果是第一次出现那么map的int类型就要为1。接下来进行第2次输入字符串,如果发现这个字符串作为下标的int值为1,那么就输出OK ,而且将这个下标记为2,如果下一次这个字符串作为下标再一次出现,且int值为2,就说明已经重复了,那么我们就输出REPEAT.如果int是其他值就说明根本没有出现过,那么就直接输出WRONG
代码如下
#include<map>
#include<cstdio>
#include<cstring>
#include<iostream>
using namespace std;
map<string ,int>a;
string s1,s2;
int n,m;
int main()
{cin>>n;while(n--){cin>>s1;a[s1]=1;}cin>>m;while(m--){cin>>s1;if(a[s1]==1){printf("OK\n");a[s1]=2;}else if(a[s1]==2){printf("REPEAT\n");}else{printf("WRONG\n");}}return 0;
}
A-B 数对
首先我们需要转换思路,题目让我求A-B=C, 我们可不可以转换为A-C=B?完全可以
为什么我们需要做这样的转化? 应为在之前A-B=C这样我们需要从一堆数据中寻找到两个符合要求的数字,而且答案是只有一个C。但是如果我们换了一个思路,B从哪里来?是不是从数组中来?答案就是在数组里面,那你就有可能会问了,那从数组里面找答案不是更加难吗?no no no。我们是不是可以用map数组,如果这个出现了一次就记录加加,我们再将数组全部都减去C这个是不是就是B,那么我们将B作为map数组下标输进去,有几次记录就有几个答案。是不是很妙?我第一次看到这样的写法我都震惊了。
代码如下
#include<iostream>
#include<cstring>
#include<map>
#include<string.h>
using namespace std;
typedef long long ll;
const int N=2e5+100;
map<ll,ll> a;
ll ans[N];
ll n,c;
int main()
{cin>>n>>c;for(int i=1;i<=n;i++){cin>>ans[i];a[ans[i]]++;//这个就是A-C=B中B的个数,其实就是在答案中找ans[i]-=c;//这个就是B,如果遍历一遍整个数组,发现在map数组中有,那么map数组中有几个,那么就出现了几次}ll anss=0;for(int i=1;i<=n;i++){anss+=a[ans[i]];}cout<<anss<<endl;return 0;
}
【模板】字符串哈希
仔细看这题 说是不是就是找有几个不同的字符串?那我们换个思路是不是就是看有几个字符串是相同的,拿着不就是和第一题差不多嘛,用一个map数组,第一个类型为string 作为下标,第二个类型为int 作为map数组具体的值,如果这个字符串出现了int 类型就进行几次加加。最后一次遍历,将int 的值为0进行累加
代码如下
#include<map>
#include<cstdio>
#include<cstring>
#include<iostream>
using namespace std;
map<string ,int>a;
string s1,s2;
int n,m;
int main()
{cin>>n;int ans=0;for(int i=1;i<=n;i++){cin>>s1;if(a[s1]==0){a[s1]=1;ans++;}}cout<<ans<<endl;return 0;
}
[USACO09OCT] Barn Echoes G
首先我看到题目并不是先想到hash的方法,我也不知道这一题用hash怎么做,反而我先想到的是用kmp算法来写 ,他题目自己说了要使用前后缀相同来写,这很自然的就想到了。这个题目有个坑点就是它没说那个是主串,那个是模式串,这两个字符串都分别作为主串和模式串来一遍kmp。
还有一个坑点就是两个模式串第一个可以是前缀,下一个是后缀。然后还可以是第二个是前缀,第一个是后缀,所以也是要使用两遍kmp算法来保证都能充当一次前缀后缀,模式串,主串。
然后用一个变量anss来记录最大的长度就可以过来了(嘿嘿 我的独创思路,还有点小自豪)
#include<iostream>
#include<cstring>
#include<string.h>
#include<algorithm>
#include<cstdio>
using namespace std;
char s1[100];
char s2[100];
int kmp[100];
int main()
{scanf("%s",s1+1);scanf("%s",s2+1);int len1=strlen(s1+1);int len2=strlen(s2+1);int j=0;for(int i=2;i<=len2;i++){while(j>0&&s2[i]!=s2[j+1])j=kmp[j];if(s2[i]==s2[j+1])j++;kmp[i]=j;}int ans=-1;j=0;for(int i=1;i<=len1;i++){while(j>0&&s1[i]!=s2[j+1])j=kmp[j];if(s1[i]==s2[j+1])j++;ans=max(ans,j); } j=0;for(int i=2;i<=len1;i++){while(j>0&&s2[i]!=s2[j+1])j=kmp[j];if(s1[i]==s1[j+1])j++;kmp[i]=j;}j=0;for(int i=1;i<=len2;i++){while(j>0&&s2[i]!=s1[j+1])j=kmp[j];if(s2[i]==s1[j+1])j++;ans=max(ans,j); } cout<<ans<<endl;return 0;
}