题目描述
如题,给定 �N 个字符串(第 �i 个字符串长度为 ��Mi,字符串内包含数字、大小写字母,大小写敏感),请求出 �N 个字符串中共有多少个不同的字符串。
友情提醒:如果真的想好好练习哈希的话,请自觉。
输入格式
第一行包含一个整数 �N,为字符串的个数。
接下来 �N 行每行包含一个字符串,为所提供的字符串。
输出格式
输出包含一行,包含一个整数,为不同的字符串个数。
输入输出样例
输入 #1复制
5 abc aaaa abc abcc 12345
输出 #1复制
4
说明/提示
对于 30%30% 的数据:�≤10N≤10,��≈6Mi≈6,����≤15Mmax≤15。
对于 70%70% 的数据:�≤1000N≤1000,��≈100Mi≈100,����≤150Mmax≤150。
对于 100%100% 的数据:�≤10000N≤10000,��≈1000Mi≈1000,����≤1500Mmax≤1500。
样例说明:
样例中第一个字符串(abc)和第三个字符串(abc)是一样的,所以所提供字符串的集合为{aaaa,abc,abcc,12345},故共计4个不同的字符串。
想法:
不了解字符串哈希,想着先用暴力写出来再说。本来的想法是一个一个字符串去遍历,就是以a[i]为标准,遍历所有字符串(除去自身),不同的话cnt就+1,然后一个a[i]弄完就更新一下min的值(min初值为0x3f3f3f3f)。最后,特判输出min的值。代码如下。
#include<bits/stdc++.h>
using namespace std;
string a[10010];
int main(){
int n;
cin>>n;
for(int i=0;i<n;i++)
cin>>a[i];
int min=0x3f3f3f3f;
for(int i=0;i<n;i++){
int cnt=1;
for(int j=0;j<n;j++){
if(a[i]!=a[j]&&i!=j)
cnt++;
}
min=min<cnt?min:cnt;
}
if(min==1) cout<<0;
else cout<<min;
}
但是吧,测试了几个例子,就发现不对了,答案应该是2吧,结果输出了3。我刚开始的想法无法解决字符串中有多个不同的字符串相同的情况,就是下面的例子,而且也会超时。
我当时就看这个例子,想着“要是能整个哈希表就好了”。就是有这么个想法,但还是不知如何实现,一大串的怎么弄呢。然后又想“要是可以把多次出现的字符串删了,只留下一个就好了”,于是就想到了。就是用一个数组初始化为1,重复出现的标为0,最后算数组中1的数量,特判一下。
#include<bits/stdc++.h>
using namespace std;
char a[10010][1510];
int hx[10010];
int main(){
int n;
cin>>n;
for(int i=0;i<n;i++){
cin>>a[i];
hx[i]=1;//用memset也行
}
for(int i=0;i<n;i++){
if(hx[i]==0) continue;
for(int j=i+1;j<n;j++){
if(hx[j]==0) continue;
if(strcmp(a[i],a[j])==0)
hx[j]=0;
}
}
int cnt=0;
for(int i=0;i<n;i++){
if(hx[i]==1) cnt++;
}
if(cnt==1) cout<<0;
else cout<<cnt;
}
学到的:
很多个string类的字符串不用写成二维数组,就像char a[1010][1010],写成string a[1010]就行了。
0x3f3f3f3f :一个十六进制数,对应的十进制为 1061109567。在计算机编程中,0x3f3f3f3f 经常被用作一个特殊的值,通常表示无穷大或者一个很大的数。这个特殊的值经常在算法中被用作初始值,例如在一些动态规划问题中,用来表示一个非常大的初始状态或者无穷大距离。在某些情况下,也可以用来代表一个特殊的标记或者占位符。
碎碎念:
本来这个题是用来学字符串哈希的,但实在是没空了,就想着先暴力写一下,写出来的时候还是很开心的,因为自己已经好久没有自己写出来题目过了。最近学dfs,bfs也遇到了很多困难,写出来的题目又不会写了,而且自己也没有理解。再加上这几天又在学科三,也很困难,没什么时间。嗐,等考完再好好学学吧,加油!不过本来心情很差的,emo了,现在倒是好点了哈哈。
1.29:
今天看了下字符串哈希,发现只是判断两个字符串是否相同的方法不一样,其他的东西和我之前想的差不多。代码如下。字符串哈希就是将字符串转化为一个数字,具体的转换方法是将字符串转换为P进制数(P为131,1331,13331等),为避免溢出,还要将最终结果模2的64次方。这些具体的数值都是为了避免哈希冲突,即两个字符串不相同但哈希值却相同。
#include<bits/stdc++.h>
using namespace std;
const int P=131;
int hx[10010];
string a[10010];
int main(){
int n;
cin>>n;
for(int i=1;i<=n;i++)
cin>>a[i];
for(int i=1;i<=n;i++){
for(int j=0;j<a[i].length();j++){
if(a[i][j]>='a'&&a[i][j]<='z')
hx[i]=(hx[i]*P+a[i][j]-'a')%(int)pow(2,64);
else if(a[i][j]>='0'&&a[i][j]<='9')
hx[i]=(hx[i]*P+a[i][j]-'0')%(int)pow(2,64);
else if(a[i][j]>='A'&&a[i][j]<='Z')
hx[i]=(hx[i]*P+a[i][j]-'A')%(int)pow(2,64);
}
//hx[i]%=(int)pow(2,64);
}
int cnt=0;
for(int i=1;i<=n;i++){
if(hx[i]==-1) continue;
for(int j=i+1;j<=n;j++){
if(hx[i]==hx[j]&&hx[j]!=-1)
hx[j]=-1;
}
}
for(int i=1;i<=n;i++){
if(hx[i]!=-1) cnt++;
}
cout<<cnt;
}
不过感觉这题的数据不是很严谨,例如下面的例子,我第一和第二个代码都ac了,但两者的答案不同。