• 力扣336.回文对 ——字符串哈希


    以此题正式学习字符串哈希,要理解并背过

    字符串哈希
    (1) 把字符换设想成一个P进制的数
    将字符串看成P进制数,P的经验值是131或13331,取这两个值的冲突概率低

    对于整数132
    1∗102+3∗10+2∗1001∗102+3∗10+2∗100
    对于字符串abcde
    a×P4+b×P3+c×P2+d×P1+e×P0a×P4+b×P3+c×P2+d×P1+e×P0
    (2) 为什么使用unsigned long long
    如果用上述P进制来存储字符串的哈希值,存在指数爆炸的情况,超出范围,而unsigned long long会将超出的部分会自动削减掉,就相当于了取模的操作,所以用这种操作来简化取模操作。取模的数用2^64,这样直接用unsigned long long存储,溢出的结果就是取模的结果。
    (3) get(int l , int r)函数:得到指定范围L——R的字符串的哈希值
    用进制运算,对于123456为例,要取得的456的哈希值需要以下操作:
    已知L指向4 R指向6,咱需要得到L-1的哈希值即为123000,用123456 - 123000即可得到456的哈希值。

     

    1. typedef unsigned long long ULL;
    2. const int P = 131;
    3. ULL h[N], p[N]; // h[k]存储字符串前k个字母的哈希值, p[k]存储 P^k mod 2^64
    4. // 计算子串str[l~r]的哈希值,l和r范围为1~n
    5. ULL get(int l, int r)
    6. {
    7. return h[r]-h[l-1]*p[r-l+1];
    8. }
    1. //对p h数组初始化
    2. p[0]=1;
    3. for(int i=1;i<=n;i++)
    4. {
    5. h[i]=h[i-1] *P +str[i];
    6. p[i]=p[i-1] *P;
    7. }

    此题代码解法

    1. typedef unsigned long long ULL;   //为了节省时间,用ULL,且超过2^64会自动取模
    2. const int N=310,P=131;     //数学里用131  13331比好好,不容易发生哈希冲突
    3. ULL p[N];  // p[k]存储 P^k mod 2^64
    4. class Solution {
    5. public:
    6.     //可以用字符串来写,也可以用字符串哈希来节省空间
    7.     vector>h1,h2; //h[k]存储字符串前k个字母的哈希值    h1存放逆向,h2是正序
    8.     ULL get(vector&h,int l,int r)   //函数计算 h数组里[l,r]的哈希值
    9.     {
    10.         return h[r]-h[l-1]*p[r-l+1];
    11.     }
    12.     vectorint>> palindromePairs(vector& words) {
    13.         p[0]=1;
    14.         for(int i=1;i//初始化p数组
    15.         {
    16.             p[i]=p[i-1]*P;
    17.         }
    18.         for(int i=0;isize();i++)
    19.         {
    20.             int n=words[i].size();
    21.             vectora(1),b(1);   //使下标从1开始
    22.             for(int j=1;j<=n;j++) a.push_back(a.back()*P+words[i][j-1]);  //以此得逆序哈希
    23.             for(int j=n;j;j--) b.push_back(b.back()*P+words[i][j-1]);  //得出正序哈希
    24.             h1.push_back(a);
    25.             h2.push_back(b);
    26.         }
    27.         unordered_mapint>hash;    //key为字符串哈希值,value是当前字符串在字符串数组的下标
    28.         for(int i=0;isize();i++)
    29.         {
    30.             hash[get(h2[i],1,words[i].size())]=i;    
    31.         }
    32.         vectorint>>res;
    33.         for(int i=0;isize();i++)
    34.         {
    35.             int n=words[i].size();
    36.             for(int j=0;j<=n;j++)
    37.             {
    38.                 auto left=get(h1[i],1,j),right=get(h1[i],j+1,n);   //h数组下标是从0开始   a,b数组下标是从1开始
    39. //有三种情况,一种是第一个单词大于等于第二个,此时前缀和第二个单词回文,后缀自己回文
    40. //第二种情况是第一个单词小于等于第二个,此时前缀和第二个单词后缀回文,第二个单词前缀自己回文
    41.                 if(right==get(h2[i],1,n-j)&&hash.count(left)&&hash[left]!=i) res.push_back({i,hash[left]});
    42.                 if(left==get(h2[i],n-j+1,n)&&hash.count(right)&&hash[right]!=i&&words[i].size()!=words[hash[right]].size())
    43.                 {
    44.                     res.push_back({hash[right],i});
    45.                 }
    46.             }
    47.         }
    48.         return res;
    49.     }
    50. };

  • 相关阅读:
    Visual Studio 2022下载、安装与运行使用方法
    腾讯云轻量应用服务器配置表汇总2核2G/2核4G/4核8G/8核16G!
    用 SwiftLint 保持 Swift 风格一致
    【C++】堆区空间的申请和释放--- 2024.3.19
    算法每日一题(反转单链表)C语言版
    python练习5
    JS sort排序
    Java虚拟机之运行时数据区(一)
    【ROS】RViz2源码分析(二):main函数及编译配置详解
    实体注解-批量生成10000条测试数据
  • 原文地址:https://blog.csdn.net/weixin_60630451/article/details/126894826