leetcode-1044:最长重复子串(滚动哈希)

leetcode-1044:最长重复子串

题目

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

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

示例 1:

输入:s = "banana"
输出:"ana"

示例 2:

输入:s = "abcd"
输出:""

解题

方法一:Rabin-Karp(滚动哈希) + 二分搜索

参考链接
leetcode-1044:最长重复子串(滚动哈希)
最后利用二分查找选择长度,因为如果长度小的子字符串sub1存在,那么它可能是长度大的子字符串sub2的子字符串
如果长度大的子字符串不存在重复,那么更大的子字符串也不可能重复。

class Solution {
public:
    uint64_t prime=31;
    string longestDupSubstring(string s) {
        int n=s.size();
		
		//滚动哈希,查找指定长度的字符串
        auto find=[&](int len){
            uint64_t hash=0;
            uint64_t power=1;
			//初始化哈希
            for(int i=0;i<len;i++){
                hash=hash*prime+s[i]-'a';
                power*=prime;
            }
            //查找哈希是否之前遇到过
            unordered_set<uint64_t> set{hash};
            for(int i=len;i<n;i++){
                hash=hash*prime-power*(s[i-len]-'a')+s[i]-'a';
                if(set.count(hash)) return i-len+1;
                set.insert(hash);
            }
            return -1;
        };

		//二分查找(选则长度)
        int l=0;
        int r=n-1;
        int pos=-1;
        int len=0;
        while(l<=r){
            int mid=(l+r)/2;
            int start=find(mid);
            if(start!=-1){
                len=mid;
                pos=start;
                l=mid+1;
            }
            else{
                r=mid-1;
            }
        }

        if(pos==-1) return "";
        return s.substr(pos,len);
    }
};

补充:
unsigned long long 是可以自动取余的,因此不会出现超过上界。为了防止哈希冲突,一般prime选择素数,然后需要更具测试集去选定。

上一篇:输出两数值,输出最大值,找最大值


下一篇:访问javaweb项目出现javax.xml .transform.T ransfomerFactoryConfiguationErmor: Provider for class javax..xml