• 哈希及其应用


    哈希算法:通过哈希函数将数据(字符串,较大的数)转化为可以用来作为数组下标的数,从而实现快速查找和匹配

    一·字符串哈希

    1.探究问题

    寻找长度为n的字符串(s1)中长度为m的字符串(s2)出现的位置(次数)

    2.解决方法

    ①枚举所有起始位置,O(m*n)

    ②字符串HASH:比较s1中的子串s3的Hash值与s2的Hash值,即比较H(s2)与H(s3)

    思考:如果我们用枚举每一个起始位置的方法计算s3的Hash值,时间复杂度并没有改观

    优化1:滚动哈希

    取两个互质常数b,M(b

    定义哈希函数H(T)=(T1*b^{n-1}+T2*b^{n-2}+...+Tn*b^{0})modM

    聪明的你发现了吗:哈希函数事实上就是把字符串看成b进制数

    设H(T,k)为字符串T中前k个字符构成字符串的Hash值

    那么子串s3=T_{k+1}...T_{k+m}的Hash值H(s3)=H(T,k+m)-H(T,k)*b^{m}

    至此,时间复杂度变为O(n+m)

    eg.

    H(1)=(T1*1)modM

    H(2)=(T1*b+T2)modM

    例题
     

    【模板】字符串哈希 - 洛谷

    1. #include
    2. #include
    3. #include
    4. #include
    5. using namespace std;
    6. typedef unsigned long long ull;
    7. ull b=131;
    8. ull mod1=1e9+7;
    9. ull mod2=1e9+9;
    10. const int N=1e5+5;
    11. struct data
    12. {
    13. ull x;
    14. ull y;
    15. }a[N];
    16. bool cmp(data m,data n)
    17. {
    18. return m.x
    19. }
    20. string str;
    21. //双哈希
    22. ull hash1(string s)
    23. {
    24. ull l=s.size(),ans=0;
    25. for(int i=0;i
    26. ans=(ans*b+(ull)s[i])%mod1;
    27. return ans;
    28. }
    29. ull hash2(string s)
    30. {
    31. ull l=s.size(),ans=0;
    32. for(int i=0;i
    33. ans=(ans*b+(ull)s[i])%mod2;
    34. return ans;
    35. }
    36. int main()
    37. {
    38. int n,i,cnt=1;
    39. cin>>n;
    40. for(i=1;i<=n;i++)
    41. {
    42. cin>>str;
    43. a[i].x=hash1(str);
    44. a[i].y=hash2(str);
    45. }
    46. sort(a+1,a+1+n,cmp);
    47. for(i=2;i<=n;i++)
    48. {
    49. if(a[i].x!=a[i-1].x||a[i].y!=a[i-1].y)
    50. cnt++;
    51. }
    52. cout<
    53. return 0;
    54. }

    3461 -- Oulipo

    1. #include
    2. #include
    3. #include
    4. #include
    5. using namespace std;
    6. typedef unsigned long long ull;
    7. const int N=1000005;
    8. const int b=131;
    9. ull p[N];
    10. ull h[N];
    11. char s1[N],s2[N];
    12. int main()
    13. {
    14. freopen("poj3461.in","r",stdin);
    15. freopen("poj3461.out","w",stdout);
    16. int i,l1,l2;
    17. ull h1;
    18. p[0]=1;
    19. for(i=1;i<=10001;i++)
    20. p[i]=p[i-1]*b;
    21. int t;
    22. scanf("%d",&t);
    23. while(t--)
    24. {
    25. scanf("%s%s",s1,s2);
    26. //s1子串 s2母串
    27. l1=strlen(s1);
    28. l2=strlen(s2);
    29. //h1子串Hash值
    30. //注意因为string这里下标是从0开始的
    31. h[0]=s2[0];
    32. for(i=1;i
    33. h[i]=h[i-1]*b+(ull)s2[i];
    34. h1=s1[0];
    35. for(i=1;i
    36. h1=h1*b+(ull)s1[i];
    37. int ans=0;
    38. if(h1==h[l1-1])ans++;
    39. for(i=1;i1;i++)
    40. {
    41. if(h1==h[i+l1-1]-h[i-1]*p[l1])
    42. ans++;
    43. }
    44. cout<
    45. }
    46. return 0;
    47. }

    注意这道题用string甚至都超时

    单词背诵 - 洛谷

    尺取法(ygp的双指针)其实就是维护一个队列包含我们想要的所有单词

     

  • 相关阅读:
    Fastflow——基于golang的轻量级工作流框架
    vue 实现前台用户登录
    E Parity Split (江西CCPC省赛)题解
    VMware workstation 中centos7虚拟机在nat模式下怎么配置网卡,指定我想要的IP并且可以联网
    linux入门---信号量
    红黑树的概念
    基于PID算法下STM32控制的坡道行驶电动小车(含源码)
    JS/TS项目里的Module都是什么?
    【Linux】 - Linux中的文件操作
    单源最短路径
  • 原文地址:https://blog.csdn.net/ESTHERWXY/article/details/125985070