最长重复子串(leetcode)

题目链接:https://leetcode-cn.com/problems/longest-duplicate-substring/

 题号:1044

题目描述:

给出一个字符串 S,考虑其所有重复子串(S 的连续子串,出现两次或多次,可能会有重叠)。

返回任何具有最长可能长度的重复子串。(如果 S 不含重复子串,那么答案为 ""。)。

示例1:

输入:"banana"
输出:"ana"

示例2:

输入:"abcd"
输出:""

题目分析:

leetcode上大佬说的:

我用具体的例子解释一下: “因此我们可以使用二分查找的方法,找到最大的 L “

这个"因此"不太显然我觉得。首先明确,二分查找的目的是:选取子串长度L,然后交给Rabin-Karp计算是否存在长度有L的重复子串,如果存在,则尝试长度更长的子串。

我懒得写题解,就用序号啦,将就看吧各位。

以题解中子任务一的示意图为例,当前串为“leetcodecookies”,长度为15,用两个指针left=1,right=15指向首尾。
(这里先提一下,left不仅仅是一个指针,二分结束时还可以通过Left得知最终的找到的最大长度l,这个地方没懂不要紧,看了下面再回过来看也行。) 通过(left
+right)/2计算mid值为8,则通过Rarbin-Karp(代码中对应(search()函数)计算是否有长度为8的重复子串。

显然没有,即search函数返回-1,说明8比最长重复子串的长度长。所以需要缩小这个长度,我们让right=mid=8
再重新计算mid,看到这里应该能感觉出来,mid值其实就是二分查找不断测试的长度值,就是“选取”。 再计算之后mid
=(1+8)/2=4,再交给search计算,search返回值仍然是-1,所以再让right=mid,再计算mid=2,此时交给seach函数返回值不为1。
说明存在长度为2的重复子串,此时应该移动left,来使得选取的mid值增大,以查看比2长的重复字串是否存在。 令left
=mid+1=3,再计算mid=(3+4)=3,再交给search,返回值为-1,不存在长度为3的重复子串,让right=mid=3,此时left=right,while终止。 所以最长重复子串长度为2,怎么计算这个长度呢?答案是left - 1。因为left的值一定是上一个成功检测到重复的mid值+1

代码:

c++:

leetcode:(超时)

PTA:

#pragma warning(disable:4996)
#include <iostream>
#include <string>
#include <unordered_map>
using namespace std;
string a;
string ans = "";
int search(int r, int l)
{
    string b;
    unordered_map<string, int>hs;
    int len = r - 1, flag;
    while (l + len <= a.length())
    {
        b = a.substr(l, len);
        if (!hs[b])
        {
            hs[b] = l;
            l++;
        }
        else
        {
            len++;
            while (l + len < a.length() && a[hs[b] + len] == a[l + len])
            {
                len++;
            }
            flag = len - 1;
            b = a.substr(l, len - 1);
            ans = b;
            if (l + len < a.length())
            {
                string c = a.substr(hs[b], len);
                string d = a.substr(l, len);
                hs[c] = hs[b];
                hs[d] = l;
                l++;//继续遍历,找出是否还有长度大于len的子串
            }
            else
                return flag;
        }
    }
    if (ans.empty())
        return 0;
    else
        return flag;
}
int main()
{
    getline(cin, a);
    a.insert(0, "!");
    int r = a.length() - 1;
    int l = 1;
    int flag = 1;
    while (l != r)
    {
        int mid = l + (r - l + 1) / 2;
        if ((flag = search(mid, flag)) && flag != 0)
            break;
        else
            r = mid - 1;
    }
    cout << flag << " " << ans;
}
/*
qwertyuqwertdfqwerty
*/
原文地址:https://www.cnblogs.com/zjw1324399/p/14319540.html