算法字符串map以及hash表
1.字符串哈希:
如果让你匹配2个字符串是否相等
一种想法就是把长度每个字符值加在一起,判断是否相等
这样ab和ba就是相等;
所以我们这边引入hash表的算法
哈希算法就是把每个字符对应一个数值,每次加上该位的x的n次幂,类似2进制的算法;
比如
”123“我们把进制设为10的话
”123“对应的就是11010+2*10+3;
一个字符串hash的算法可以变为:
ull hash(string s)
{
ull ans=1;
for(int i=0;i<s.size();++i)
{
ans=(ans*x+(ull)s[i])%mod;
}
return ans;
}
模拟上诉过程,这里的x选择有技巧哦,实验发现像131
1331,13331,1333331这样的数乘上去,就少了哈希冲突具体可以看看其它人博客什么叫哈希冲突;
接下来如果数值很大的话,我们要取余数一般对2的64取余数,unsinged long long的最大值;
ull mod=212370440130137957ll;
接下来就是代码,2个数的哈希值不一样,数字就不一样;
#include <iostream>
#include <string>
#include <algorithm>
using namespace std;
typedef unsigned long long ull;
ull x=13331;
ull mod=212370440130137957ll;
ull hash(string s)
{
ull ans=1;
for(int i=0;i<s.size();++i)
{
ans=(ans*x+(ull)s[i])%mod;
}
return ans;
}
ull a[10010];
int main()
{
ull n;cin>>n;
string s;
int i=0;
while(n)
{
cin>>s;
a[i++]=hash(s);
n--;
}
sort(a,a+i);
int ans=0;
for(int j=0;j<i;++j)
{
if(a[j]!=a[j+1])
ans++;
}
cout<<ans;
return 0;
}
2.map绑定2个类型结构体:
题目:洛谷密码
思路:
1.因为一个单词和数字相匹配,一路看过来我写的blog的人都知道这个是个小技巧,多个属性在一起的时候就用一个结构体把他们绑定在一起这里有2个stl的结构体;
map绑定2个随意类型,pair绑定2个int类型:
这里一个单词绑定一个数值
map<string,int>
2.每次输入一个值,就把对应得int存入数组;
3.sort排序;
代码:
/*
1.输入字符串
2.每个字符串如果在map里面就在用一个int数组里面存入这个值
3.sort,然后输出;
*/
#include <iostream>
#include <map>
#include <algorithm>
using namespace std;
int y[10010],top=0;
int main()
{
map<string,int>q;
q["one"]=1;q["two"]=2;q["three"]=3;q["four"]=4;q["five"]=5;q["six"]=6;q["seven"]=7;q["eight"]=8;q["nine"]=9;q["ten"]=10;
q["eleven"]=11;q["twelve"]=12;q["thirteen"]=13;q["fourteen"]=14;q["fifteen"]=15;q["sixteen"]=16;q["seventeen"]=17;q["eighteen"]=18;q["nineteen"]=19;q["twenty"]=20;
q["a"]=1;q["both"]=2;q["another"]=1;q["first"]=1;q["second"]=2;q["third"]=3;
string s;
for(int i=0;i<6;++i)
{
cin>>s;
if(q[s]!=0)
{
int k=q[s]*q[s]%100;
if(k==0)continue;
y[++top]=k;
}
}
sort(y,y+top);
cout<<y[0];
for(int i=1;i<=top;i++){
if(y[i]<10)cout<<0;
cout<<y[i];
}
return 0;
}
这里只要输入一个字符串,存在,就把对应的数字存入,然后排序;
3.sscanf以及sprintf妙用
题目:口算练习题
思路:
1*.利用一个string 存入第一个输入的值*,这里注意不要用
char,为什么呢?因为第一个如果是数字的话,char存下来就不能把这个数字转化成int的整数了;
2.sprintf将数组输入到字符串,
eg.
sprintf(数组名称,”%d+%d=%d,a,b,a+b);
这里数组存入的就是[%d,+,%d,=,%d];%d会被占位掉;
3.sscanf输入变化:
eg sscanf(s,"%d",&a);
把s以%d存入到整数a里面去;
/*
1.输入一个字符串;
2,如果是a b c输入2个整数输出;
3.不是的话,就把第一个数转化为int,查看上一次的char是什么;
*/
#include <iostream>
#include <string>
#include <cstring>
#include <cstdio>
using namespace std;
char m[100010];
char s[10010];
int main()
{
char t;
int n,a,b;cin>>n;
while(n)
{
cin>>s;
memset(m,0,sizeof(m));
if(s[0]=='a')
{
cin>>a>>b;
cout<<a<<"+"<<b<<"="<<a+b<<endl;
sprintf(m,"%d+%d=%d",a,b,a+b);
cout<<strlen(m)<<endl;
t='+';
}
else if(s[0]=='b')
{
cin>>a>>b;
cout<<a<<"-"<<b<<"="<<a-b<<endl;
sprintf(m,"%d-%d=%d",a,b,a-b);
cout<<strlen(m)<<endl;
t='-';
}
else if(s[0]=='c')
{
cin>>a>>b;
cout<<a<<"*"<<b<<"="<<a*b<<endl;
sprintf(m,"%d*%d=%d",a,b,a*b);
cout<<strlen(m)<<endl;
t='*';
}
else
{
sscanf(s,"%d",&a);
cin>>b;
if(t=='+')
{
cout<<a<<"+"<<b<<"="<<a+b<<endl;
sprintf(m,"%d+%d=%d",a,b,a+b);
cout<<strlen(m)<<endl;
}
else if(t=='-')
{
cout<<a<<"-"<<b<<"="<<a-b<<endl;
sprintf(m,"%d-%d=%d",a,b,a-b);
cout<<strlen(m)<<endl;
}
else if(t=='*')
{
cout<<a<<"*"<<b<<"="<<a*b<<endl;
sprintf(m,"%d*%d=%d",a,b,a*b);
cout<<strlen(m)<<endl;
}
}
n--;
}
}
只要注意string不能符合到sscanf这个里面去:用char s[]
cin>>s;
好了 字符串博大精深,大家加油,午安,打工人。
周末有空的话再更新一下kmp算法hash的应用;