欢迎使用本站,预祝练习时长两年半的选手们到成功! [本模块信息来自tem/def/head]

class01 yzo 哈希 提高

时间:2024-05-22 21:03 作者:admin 点击:
1、时间复杂度:是衡量算法优劣的一项标准 通常 T=O(n) ,在数学中类似 y=f(x) f(x)=3*x - y=3*x - 随着x逐渐增大,y也会逐渐增大,在坐标系上呈现直线 T=O(n) 随着数据量n逐渐变化,时间复杂

1、时间复杂度:是衡量算法优劣的一项标准

通常 T=O(n) ,在数学中类似 y=f(x)

f(x)=3*x -> y=3*x -> 随着x逐渐增大,y也会逐渐增大,在坐标系上呈现直线

T=O(n) 随着数据量n逐渐变化,时间复杂度T也会逐渐变化,这里的O时间复杂度函数

时间复杂度是指基本代码执行的次数,基本代码通常指循环最里层的代码


输入一个n,输入n个数字,将n个数字变成相反数再输出

for(int i=0;i<n;i++){

   cout<<-a[i]<<" ";//基本代码

}

T=O(n) 随着n逐渐增大,T也逐渐增大


输入一个n,输入n个数字,将n个数字从小到大排序再输出

for(int i=0;i<n;i++){

   for(int j=0;j<n-i;j++){

       if(a[j]>a[j+1]) swap(a[j],a[j+1]);//基本代码

   }

}

T=O(n^2) 随着n逐渐增大,T也逐渐增大,增大的幅度逐渐变大


输入一个n,输入n个数字(有序),输入一个m,输出m是否在这n个数中

int l=0,r=n-1;

while(l<r){

   int mid=(l+r)/2;

   if(...) ..;

   else ..;

}

T=O(logn) 数学的对数函数,c++底数通常忽略,随着n逐渐增大,T也逐渐增大,增大的幅度逐渐变变小


递归求斐波那契数列

int feib(int n){

   if(n<2) return 1;

   return feib(n-1)+fei(n-2);

}

T=O(2^n) 随着n逐渐增大,T也逐渐增大,增大的幅度逐渐变大


输入一个数字,输出它是奇数还是偶数

T=O(1) 时间复杂度T,与数据量没关系,通常记作常数级,O(1)


时间复杂度是【估算】

平面直角坐标系:略

O(1)>O(logn)>O(n)>O(nlogn)>O(n^2)>O(2^n)>O(n!)

O(nlogn) 是快速排序的平均时间复杂度(与基准数字的具体数值有关)


---------------------------------------------------

2、字符串哈希

输入n,输入n个数字,输入m,在这n个数字中,m是否存在

for(int i=0;i<n;i++){

   if(a[i]==m)...;

}

解法:O(n)

先排序sort O(nlogn),再二分 O(logn),因为O((n+1)logn)与O(nlogn)接近,

所以可以认为这样的解法符合O(nlogn)。


输入n,输入n个字符串,字符串的长度为k,输入字符串m,在这n个字符串中,m是否存在

for(int i=0;i<n;i++){

   if(a[i]==m)...;

}

因为字符串判断时间复杂度是O(n),因此该解法为O(nk)

字符串连接,长度n*k,再find,时间复杂度还是O(nk)

若O(nk)超时了,怎么办?

将字符串看成数字

字符串哈希:将一个字符串转化成一个整数,并且保证每个字符串转化的整数都不同,这个整数就是这个字符串的哈希值

这样可以通过哈希值判断字符串是否出现过,时间复杂度降低到O(n)

如:abc 1 bca 2 ccc 3      mkk 6

将字符串转化成哈希值的函数,也叫哈希函数

哈希冲突率:计算哈希值时,有一定概率使不同字符串的哈希值相同,这个叫做哈希冲突

如:

//返回长度

int hash1(string s){

   return s.size();

}

abc=3 ccc=3 bac=3 哈希冲突率越小,哈希函数越完美

//返回每个字符的ascii之和

int hash2(string s){

   int hs=0;

   for(int i=0;i<s.size();i++){

       hs+=s[i];

   }

   return hs;

}

abc=bac=cba=294

//将计算哈希值的方法逐渐优化,降低哈希冲突率

int hash3(string s){

   int hs=0;

   for(int i=0;i<s.size();i++){

       hs=hs*10+s[i];

   }

   return hs;

}

修改先后次序的权重,实现abc、bac、cba哈希值不同

int hash4(string s){

   int hs=0;

   for(int i=0;i<s.size();i++){

       hs=hs*128+s[i];

   }

   return hs;

}

//将字符组成的字符串根据ascii码的值看成128进制

int n;

cin>>n;

string s,m;

int a[100000]={};

for(int i=0;i<n;i++){

   cin>>s;

   a[i]=hash4(s);

}

cin>>m;

int b=hash4(m);

for(int i=0;i<n;i++){

   if(b==a[i]) ..;

}

//写哈希算法(保证只有小写字母)

int getchs(char c){

   return c-'a'+1;//降低值

}

//进制的选择:通常需要比数据种类大,通常取质数

//26个字母29,128个字符131,256个字符257

int jz=29;

int mod=1000000007;//超过范围进行取模

//hash("abc")=hash("ab")*jz+getchs('c')

string s="abcdefgh";//

vector<long long> hs(s.size()+1,0);//长度,初始值

vector<long long> hss;//多个字符串的哈希值

void hashqz(string s){

   //一次遍历计算出所有前缀哈希值,hs[s.size()]代表s的哈希值

   for(int i=1;i<=s.size();i++){

       hs[i]=(hs[i-1]*jz+getchs(s[i-1]))%mod;

       //0+1=>0*10+1=1

       //1+2=>1*10+2=12

       //12+3=>12*10+3=123

   }

   hss.push_back(hs[s.size()]);

}

void hashhz(string s){

   //一次遍历计算出所有后缀哈希值,hs[s.size()]代表s的哈希值

   //3=>3

   //2+3=>2*10+3

   //1+23=>1*100+23

   //hs["abc"]=getchs('a')*jz^?+hs["bc"]

   int jzs=1;

   for(int i=s.size()-1;i>=0;i--){

       hs[s.size()-i]=(getchs(s[i])*jzs+hs[s.size()-i-1])%mod;

       //hs[0]=0, c->3 hs[1]=3*1+hs[0]=

       //jzs->29, b->2 hs[2]=2*29+hs[1]=

       //jzs->29^2, a->1 hs[3]=1*29^2+hs[2]=

       jzs*=jz;

       jzs%=mod;

   }

}

int main(){

   int n;

   cin>>n;

   for(int i=0;i<n;i++){

       cin>>s;

       hashqz(s);

   }

}

abc 3 23 123



作业:

自己梳理并完成:输入一个字符串,输出所有前缀和后缀哈希值的程序

完成:ybt.ssoier.cn:8088/problem_show.php?pid=1458

(责任编辑:admin)
    顶一下
    (0)
    0%
    踩一下
    (0)
    0%