Leetcode 1044 最长重复子串

题目

给你一个字符串 s ,考虑其所有 重复子串 :即,s 的连续子串,在 s 中出现 2 次或更多次。这些出现之间可能存在重叠。

返回 任意一个 具有最长长度的重复子串。如果 s 不含重复子串,那么答案为 “” 。

解题思路

  如果枚举重复子串的长度,用滑动窗口和哈希来判重,必定超时。我们有两个可以优化的地方。

  • 第一个是枚举重复子串的长度,对于这个长度,大于这个长度的子串中必定不会出现重复子串,小于这个长度的子串中必定会出现重复字串,其具有二分性,那么这里可以用到二分,这里变成了O( l o g n logn logn)。
  • 第二个可以优化的地方是哈希判重,如果直接用 Set<String> 来维护,由于子串存进容器的哈希函数执行与子串的长度有关,复杂度最坏可能达到O( n {n} n),由于枚举滑动窗口的时间复杂度是O( n n n),所以总时间复杂度变成了O( n 2 l o g n n^2logn n2logn),会超时。比较好的做法是用字符串哈希,其基本思想是把字符串转换成P进制数,对于字符串保证每个子串的值唯一。可以看看三叶姐的字符串哈希入门。由此可以把哈希查询的复杂度降为O( 1 1 1),算上之前的时间复杂度为O( n l o g n nlogn nlogn)。
代码
class Solution {
    public long[] pos, hash;
    int length, P = 13131;
    String ans, s;

    public String longestDupSubstring(String s) {
        char[] chars = s.toCharArray();

        init(s);

        pos[0] = 1;
        for (int i = 1; i <= length; i++) {
            pos[i] = pos[i - 1] * P;
            hash[i] = hash[i - 1] * P + chars[i - 1] - 'a' + 1;
        }

        int left = 0, right = length;
        while (left < right) {
            int mid = left + right + 1 >> 1;
            if (check(mid)) left = mid;
            else right = mid - 1;
        }
        return ans;
    }

    private void init(String s) {
        this.s = s;
        ans = "";
        length = s.length();
        pos = new long[length + 50];
        hash = new long[length + 50];
    }

    private boolean check(int mid) {
        Set<Long> set = new HashSet<>();
        for (int i = 1; i + mid - 1 <= length; i++) {
            int j = i + mid - 1;
            long now = hash[j] - hash[i - 1] * pos[j - i + 1];
            if (set.contains(now)) {
                ans = ans.length() > mid ? ans : s.substring(i - 1, j);
                return true;
            }
            set.add(now);
        }
        return false;
    }
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值