• 力扣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. };

  • 相关阅读:
    Unity包围盒
    网络安全:使用各类编码混淆攻击
    《深入浅出Spring》bean 生命周期
    网上零食销售系统(Java;JSP;JDBC)附源码+数据库+论文
    jsp页面出现“String cannot be resolved to a type”错误解决办法
    【C语言基础】:深入理解指针(终篇)
    Apache Doris 2.1.2 版本正式发布!
    前端面试题: js中对比两个对象的值是否相等? for..in 和 for...of的区别?
    CAD插件的安装和自动加载dll、arx
    Java面向对象2
  • 原文地址:https://blog.csdn.net/weixin_60630451/article/details/126894826