LeetCode5803. 最长公共子路径(哈希+二分)

Posted live4m

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了LeetCode5803. 最长公共子路径(哈希+二分)相关的知识,希望对你有一定的参考价值。

题意:

一个国家由 n 个编号为 0 到 n - 1 的城市组成。在这个国家里,每两个 城市之间都有一条道路连接。

总共有 m 个编号为 0 到 m - 1 的朋友想在这个国家旅游。他们每一个人的路径都会包含一些城市。
每条路径都由一个整数数组表示,每个整数数组表示一个朋友按顺序访问过的城市序列。
同一个城市在一条路径中可能 重复 出现,但同一个城市在一条路径中不会连续出现。

给你一个整数 n 和二维数组 paths ,
其中 paths[i] 是一个整数数组,表示第 i 个朋友走过的路径,
请你返回 每一个 朋友都走过的 最长公共子路径 的长度,如果不存在公共子路径,请你返回 0 。

一个 子路径 指的是一条路径中连续的城市序列。

数据范围:
1 <= n <= 1e5
m == paths.length
2 <= m <= 1e5
sum(paths[i].length) <= 1e5
0 <= paths[i][j] < n
paths[i] 中同一个城市不会连续重复出现。

解法:

二分答案mid,
哈希+map,对于路径[0,m-1],
对于path[i],枚举所有长度为mid的子路径,
如果map中该路径的哈希值已经被标记为i,那么更新为i+1.
只要某个哈希值被标记到m了,就说明存在长度为mid的子路径,在所有人的路径中都出现过.

二分复杂度O(log),check复杂度O(1e5*log).
总复杂度O(1e5*log*log).

code:

#define PI pair<int,int>
const int maxm=1e5+5;
const int mod1=1e9+7;
const int mod2=1e9+9;
const int p1=1331;
const int p2=131;
int base1[maxm];
int base2[maxm];
class Solution {
public:
    vector<vector<int> >p;
    vector<vector<int> >h1,h2;
    int n,m;
    bool check(int mid){
        map<PI,int>mp;
        for(int i=0;i<m;i++){
            int len=p[i].size();
            for(int j=mid-1;j<len;j++){
                int l=j-mid+1,r=j;
                int H1=((h1[i][r]-(l==0?0:1ll*base1[r-l+1]*h1[i][l-1]))%mod1+mod1)%mod1;
                int H2=((h2[i][r]-(l==0?0:1ll*base2[r-l+1]*h2[i][l-1]))%mod2+mod2)%mod2;
                if(i==0){
                    mp[{H1,H2}]=1;
                }else if(mp.count({H1,H2})&&mp[{H1,H2}]==i){
                    if(i==m-1)return 1;
                    else mp[{H1,H2}]=i+1;
                }
            }
        }
        return 0;
    }
    int solve(){
        //init
        base1[0]=1;
        for(int i=1;i<maxm;i++)base1[i]=1ll*base1[i-1]*p1%mod1;
        base2[0]=1;
        for(int i=1;i<maxm;i++)base2[i]=1ll*base2[i-1]*p2%mod2;
        //
        for(int i=0;i<m;i++){
            int len=p[i].size();
            h1[i].resize(len);
            h2[i].resize(len);
            for(int j=0;j<len;j++){
                if(j==0){
                    h1[i][j]=p[i][j]+1;
                    h2[i][j]=p[i][j]+1;
                }else{
                    h1[i][j]=(1ll*h1[i][j-1]*p1%mod1+(p[i][j]+1))%mod1;
                    h2[i][j]=(1ll*h2[i][j-1]*p2%mod2+(p[i][j]+1))%mod2;
                }
            }
        }
        //
        int ans=0;
        int l=1,r=p[0].size();
        while(l<=r){
            int mid=(l+r)/2;
            if(check(mid))ans=mid,l=mid+1;
            else r=mid-1;
        }
        return ans;
    }
    int longestCommonSubpath(int nn, vector<vector<int>>& pp) {
        n=nn,p=pp,m=pp.size();
        h1.resize(m);h2.resize(m);
        int ans=solve();
        return ans;
    }
};

以上是关于LeetCode5803. 最长公共子路径(哈希+二分)的主要内容,如果未能解决你的问题,请参考以下文章

LeetCode(LCSி)最长公共子序列&变形应用

Leetcode——最长重复数组(最长公共子串) / 最长重复子串

poj 2774 字符串哈希求最长公共子串

LeetCode 1143 最长公共子序列

Leetcode 1143 最长公共子序列

《LeetCode之每日一题》:106.最长公共子序列