2021-07-04 5803周赛

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

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

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

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

示例 1:

输入:n = 5, paths = [[0,1,2,3,4],
[2,3,4],
[4,0,1,2,3]]
输出:2
解释:最长公共子路径为 [2,3] 。

示例 2:

输入:n = 3, paths = [[0],[1],[2]]
输出:0
解释:三条路径没有公共子路径。

示例 3:

输入:n = 5, paths = [[0,1,2,3,4],
[4,3,2,1,0]]
输出:1
解释:最长公共子路径为 [0],[1],[2],[3] 和 [4] 。它们长度都为 1 。

提示:

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

来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/longest-common-subpath

class Solution {
    public int longestCommonSubpath(int n, int[][] paths) {
        int left = 1,right = getMin(paths);
        Random rand = new Random();
        long base = 135721;//100000 + rand.nextInt(1000000-100000+1);
        long mod = Long.MAX_VALUE;
        long muti = 0;
        int ans = 0;
        while(left<=right){
            int mid = (left+right)/2;
            muti = pow(base,mid,mod);
            Set<Long> set = new HashSet<>();
            for(int i=0 ; i<paths.length ; i++){
                long hash = 0;
                Set<Long> tmp = new HashSet<>();
                for(int j=0 ; j<mid ; j++){
                    hash = (hash*base + paths[i][j])%mod;
                }
                if(i==0 || set.contains(hash)){
                        tmp.add(hash);
                }
                
                for(int j=mid ; j<paths[i].length ; j++){
                   hash = (hash*base + paths[i][j] - muti*paths[i][j-mid])%mod;
                   if(i==0 || set.contains(hash)){
                        tmp.add(hash);
                    }
                }
                set = tmp;
                if(set.isEmpty()){
                    break;
                }
            }
            if(set.isEmpty()){
                right = mid-1;
            } else{
                left = mid+1;
                ans = mid;
            }         
        }
        return ans;
    }

    int getMin(int[][] paths){
        int min = paths[0].length;
        for(int[] path : paths){
            min = Math.min(path.length,min);
        }
        return min;
    }

    long pow(long base,long n,long mod){
        long res = 1;
        for(int i=0 ; i<n ; i++){
            res = (res * base)%mod;
        }
        return res;
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值