字符串哈希

题目传送门

解题思路:
二分+双模哈希
记忆出错的几个点:

  1. p和h数组都为long类型
  2. p[0] = 1必须加上
  3. 第一次计算所有h[i]时,新添加的数字必须从1开始,不能从0开始。
  4. 求固定长度为k的cur子串哈希值时,记得
    long cur1 = ((h1[i][t]-h1[i][j-1]*p1[k])%mo1+mo1)%mo1;
    当前计算的是字符串path[i]中下标为j-1开头,长度为k的字符串的哈希值,同时为了防止相减后出现负数,需要取模后加模再取模。
class Solution {
    int m;
    int max_len = 0;
    long power = 13131;
    long mo1 = 1e9+13,mo2 = 1e9+7;
    vector<int>p1 = vector<int>(100000,0);
    vector<int>p2 = vector<int>(100000,0);
public:
    int longestCommonSubpath(int n, vector<vector<int>>& paths) {
        m = paths.size();
        vector<long>v;
        vector<vector<long>>h1(m,v);
        vector<vector<long>>h2(m,v);
        int l = 0,r = INT_MAX;
        for(int i = 0;i<m;i++){
            int len = paths[i].size();
            r = min(r,len);
            h1[i] = vector<long>(len+5,0);
            h2[i] = vector<long>(len+5,0);
            for(int j = 0;j<len;j++){
            	//这里的+1对应上述易错点3
                h1[i][j+1] = (h1[i][j]*power+paths[i][j]+1)%mo1;
                h2[i][j+1] = (h2[i][j]*power+paths[i][j]+1)%mo2;
            }
        }
        p1[0] = 1;
        p2[0] = 1;
        for(int i = 0;i<r;i++){
            p1[i+1] = p1[i]*power%mo1;
            p2[i+1] = p2[i]*power%mo2;
        }
        while(l<r){
            int mid = (l+r+1)>>1;
            if(func(mid,paths,h1,h2)){
                l = mid;
            }else{
                r = mid-1;
            }
        }
        return r;
    }
private:
    bool func(int k,vector<vector<int>>& paths,vector<vector<long>>& h1,vector<vector<long>>& h2){
        unordered_set<long>info1,info2,info3,info4;
        for(int i = 0;i<m;i++){
            if(i != 0 && info1.size() == 0){
                return false;
            }
            int len = paths[i].size();
            if(len<k)   return false;
            for(int j = 1;j+k-1<=len;j++){
                int t = j+k-1;
                long cur1 = ((h1[i][t]-h1[i][j-1]*p1[k])%mo1+mo1)%mo1;
                long cur2 = ((h2[i][t]-h2[i][j-1]*p2[k])%mo2+mo2)%mo2;
                if(i == 0){
                    info1.insert(cur1);
                    info2.insert(cur2);
                }else{
                    if(info1.find(cur1) != info1.end() && info2.find(cur2) != info2.end()){
                        info3.insert(cur1);
                        info4.insert(cur2);
                    }
                }
            }
            if(i != 0){
                swap(info1,info3);
                swap(info2,info4);
                info3.clear();
                info4.clear();
            }
        }
        if(info1.size() == 0){
            return false;
        }else
            return true;
    }
};
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值