【滚动哈希 二分查找】1044. 最长重复子串

本文涉及知识点

滚动哈希
二分查找算法合集

LeetCode 1044. 最长重复子串

给你一个字符串 s ,考虑其所有 重复子串 :即 s 的(连续)子串,在 s 中出现 2 次或更多次。这些出现之间可能存在重叠。
返回 任意一个 可能具有最长长度的重复子串。如果 s 不含重复子串,那么答案为 “” 。
示例 1:
输入:s = “banana”
输出:“ana”
示例 2:
输入:s = “abcd”
输出:“”
提示:
2 <= s.length <= 3 * 104
s 由小写英文字母组成

二分查找+滚动哈希

令 Check(len) 返回 是否存在长度为len的重复字符串
len1 < len2,如果Check(len2)为true,则Check(len1)一定为true
即 len ∈ \in [0,len3]为Check(len)为true,len ∈ \in [len3+1,n] Check(len)为false。
寻找最后一个true,故用左闭右开空间。

Check函数

len = 0 为0,返回true。
用滚动函数计算 s[i…i+len-1]的哈希值, i+ len <= s.length 并将哈希值记录到set中,如果存在重复值,返回true。

时间复杂度:O(nlogn)
二分查找:O(logn) Check函数O(n)

代码

核心代码

template<int MOD = 1000000007>
class C1097Int
{
public:C1097Int(long long llData = 0) :m_iData(llData% MOD){}C1097Int  operator+(const C1097Int& o)const{return C1097Int(((long long)m_iData + o.m_iData) % MOD);}C1097Int& operator+=(const C1097Int& o){m_iData = ((long long)m_iData + o.m_iData) % MOD;return *this;}C1097Int& operator-=(const C1097Int& o){m_iData = (m_iData + MOD - o.m_iData) % MOD;return *this;}C1097Int  operator-(const C1097Int& o){return C1097Int((m_iData + MOD - o.m_iData) % MOD);}C1097Int  operator*(const C1097Int& o)const{return((long long)m_iData * o.m_iData) % MOD;}C1097Int& operator*=(const C1097Int& o){m_iData = ((long long)m_iData * o.m_iData) % MOD;return *this;}C1097Int  operator/(const C1097Int& o)const{return *this * o.PowNegative1();}C1097Int& operator/=(const C1097Int& o){*this /= o.PowNegative1();return *this;}bool operator==(const C1097Int& o)const{return m_iData == o.m_iData;}bool operator<(const C1097Int& o)const{return m_iData < o.m_iData;}C1097Int pow(long long n)const{C1097Int iRet = 1, iCur = *this;while (n){if (n & 1){iRet *= iCur;}iCur *= iCur;n >>= 1;}return iRet;}C1097Int PowNegative1()const{return pow(MOD - 2);}int ToInt()const{return m_iData;}
private:int m_iData = 0;;
};//iCodeNum 必须大于等于可能的字符数
template<int MOD = 1000000007>
class CHashStr {
public:CHashStr(string s, int iCodeNum, int iCodeBegin = 1, char chBegin = 'a') {m_c = s.length();m_vP.resize(m_c + 1);m_vP[0] = 1;m_vHash.resize(m_c + 1);for (int i = 0; i < m_c; i++){const int P = iCodeBegin + iCodeNum;m_vHash[i + 1] = m_vHash[i] * P + s[i] - chBegin + iCodeBegin;m_vP[i + 1] = m_vP[i] * P;}}//iMinValue将被编码为0,iMaxValue被编码为iMaxValue-iMinValue。CHashStr(const int* data, int len, int iMinValue = 0, int iMaxValue = 9) {m_c = len;m_vP.resize(m_c + 1);m_vP[0] = 1;m_vHash.resize(m_c + 1);const int P = iMaxValue - iMinValue + 1;for (int i = 0; i < m_c; i++){const int iCurCode = data[i] - iMinValue;assert((iCurCode >= 0) && (iCurCode < P));m_vHash[i + 1] = m_vHash[i] * P + iCurCode;m_vP[i + 1] = m_vP[i] * P;}}//包括left rightint GetHash(int left, int right){return (m_vHash[right + 1] - m_vHash[left] * m_vP[right - left + 1]).ToInt();}inline int GetHash(int right){return m_vHash[right + 1].ToInt();}int GetHashExincludeRight(int left, int right){return (m_vHash[right] - m_vHash[left] * m_vP[right - left]).ToInt();}inline int GetHashExincludeRight(int right){return m_vHash[right].ToInt();}int m_c;vector<C1097Int<MOD>> m_vP;vector<C1097Int<MOD>> m_vHash;
};template<int MOD2 = 1000000009>
class C2HashStr
{
public:C2HashStr(string s) {m_pHash1 = std::make_unique<CHashStr<>>(s, 26);m_pHash2 = std::make_unique < CHashStr<MOD2>>(s, 27, 0);}C2HashStr(const int* data, int len, int iMinValue = 0, int iMaxValue = 9){m_pHash1 = std::make_unique<CHashStr<>>(data, len, iMinValue, iMaxValue);m_pHash2 = std::make_unique < CHashStr<MOD2>>(data, len, iMinValue, iMaxValue);}//包括left rightlong long GetHash(int left, int right){return (long long)m_pHash1->GetHash(left, right) * (MOD2 + 1) + m_pHash2->GetHash(left, right);}long long GetHash(int right){return (long long)m_pHash1->GetHash(right) * (MOD2 + 1) + m_pHash2->GetHash(right);}//包括Left,不包括Rightlong long GetHashExincludeRight(int left, int right){return (long long)m_pHash1->GetHashExincludeRight(left, right) * (MOD2 + 1) + m_pHash2->GetHashExincludeRight(left, right);}long long GetHashExincludeRight(int right){return (long long)m_pHash1->GetHashExincludeRight(right) * (MOD2 + 1) + m_pHash2->GetHashExincludeRight(right);}
private:std::unique_ptr<CHashStr<>> m_pHash1;std::unique_ptr<CHashStr<MOD2>> m_pHash2;
};namespace NBinarySearch
{template<class INDEX_TYPE, class _Pr>INDEX_TYPE FindFrist(INDEX_TYPE left, INDEX_TYPE rightInclue, _Pr pr){while (rightInclue - left > 1){const auto mid = left + (rightInclue - left) / 2;if (pr(mid)){rightInclue = mid;}else{left = mid;}}return rightInclue;}template<class INDEX_TYPE, class _Pr>INDEX_TYPE FindEnd(INDEX_TYPE leftInclude, INDEX_TYPE right, _Pr pr){while (right - leftInclude > 1){const auto mid = leftInclude + (right - leftInclude) / 2;if (pr(mid)){leftInclude = mid;}else{right = mid;}}return leftInclude;}
}class Solution {
public:string longestDupSubstring(string s) {string ret;C2HashStr<> dh(s);auto Check = [&](int len) {if (0 == len) { ret = ""; return true; }unordered_set<long long> setHas;for (int i = 0; i + len <= s.length(); i++) {auto cur = dh.GetHashExincludeRight(i, i + len);if (setHas.count(cur)) {ret = s.substr(i, len);return true;}setHas.emplace(cur);}return false;};NBinarySearch::FindEnd(0, (int)s.length() + 1, Check);return ret;}
};

单元测试

template<class T1,class T2>
void AssertEx(const T1& t1, const T2& t2)
{Assert::AreEqual(t1 , t2);
}template<class T>
void AssertEx(const vector<T>& v1, const vector<T>& v2)
{Assert::AreEqual(v1.size(), v2.size());	for (int i = 0; i < v1.size(); i++){Assert::AreEqual(v1[i], v2[i]);}
}template<class T>
void AssertV2(vector<vector<T>> vv1, vector<vector<T>> vv2)
{sort(vv1.begin(), vv1.end());sort(vv2.begin(), vv2.end());Assert::AreEqual(vv1.size(), vv2.size());for (int i = 0; i < vv1.size(); i++){AssertEx(vv1[i], vv2[i]);}
}namespace UnitTest
{string s;TEST_CLASS(UnitTest){public:TEST_METHOD(TestMethod1){s = "banana";auto res = Solution().longestDupSubstring(s);AssertEx(string("ana"), res);}TEST_METHOD(TestMethod2){s = "abcd";auto res = Solution().longestDupSubstring(s);AssertEx(string(""), res);}TEST_METHOD(TestMethod3){s = "aa";auto res = Solution().longestDupSubstring(s);AssertEx(string("a"), res);}	};
}

扩展阅读

视频课程

先学简单的课程,请移步CSDN学院,听白银讲师(也就是鄙人)的讲解。
https://edu.csdn.net/course/detail/38771

如何你想快速形成战斗了,为老板分忧,请学习C#入职培训、C++入职培训等课程
https://edu.csdn.net/lecturer/6176

相关推荐

我想对大家说的话
《喜缺全书算法册》以原理、正确性证明、总结为主。
按类别查阅鄙人的算法文章,请点击《算法与数据汇总》。
有效学习:明确的目标 及时的反馈 拉伸区(难度合适) 专注
闻缺陷则喜(喜缺)是一个美好的愿望,早发现问题,早修改问题,给老板节约钱。
子墨子言之:事无终始,无务多业。也就是我们常说的专业的人做专业的事。
如果程序是一条龙,那算法就是他的是睛

测试环境

操作系统:win7 开发环境: VS2019 C++17
或者 操作系统:win10 开发环境: VS2022 C++17
如无特殊说明,本算法用**C++**实现。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/pingmian/31891.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

嵌合抗体设计与表达服务:哺乳细胞重组表达的利器

嵌合抗体是一类具有重要生物学功能和药物研发应用的蛋白质&#xff0c;其设计和表达对于相关研究至关重要。本文将介绍嵌合抗体设计与表达服务的原理和方法&#xff0c;重点关注哺乳细胞重组表达的技术进展和应用。 嵌合抗体设计与表达服务 嵌合抗体设计服务是通过计算机辅助…

webid、sec_poison_id、a1、web_session参数分析与算法实现

文章目录 1. 写在前面2. 参数分析3. 核心算法【🏠作者主页】:吴秋霖 【💼作者介绍】:擅长爬虫与JS加密逆向分析!Python领域优质创作者、CSDN博客专家、阿里云博客专家、华为云享专家。一路走来长期坚守并致力于Python与爬虫领域研究与开发工作! 【🌟作者推荐】:对爬…

基于SSM+Jsp的体育竞赛成绩管理系统

开发语言&#xff1a;Java框架&#xff1a;ssm技术&#xff1a;JSPJDK版本&#xff1a;JDK1.8服务器&#xff1a;tomcat7数据库&#xff1a;mysql 5.7&#xff08;一定要5.7版本&#xff09;数据库工具&#xff1a;Navicat11开发软件&#xff1a;eclipse/myeclipse/ideaMaven包…

NetSuite Non-Inventory Item 公司内外采购总账影响

上篇文章提到&#xff0c;Non-Inventory Item的科目维护会根据各个企业的实际情况而有所不同&#xff0c;通常情况下都涉及外部交易&#xff0c;即对外采购与销售&#xff1b;另外也涉及到公司内部的相关交易&#xff0c;本篇以采购为例&#xff0c;来看看公司内外采购交易所对…

Bootstrap 标签

Bootstrap 标签 引言 Bootstrap 是一个流行的前端框架,它提供了一套丰富的组件和工具,帮助开发者快速构建响应式和移动优先的网页。在 Bootstrap 中,标签(Badge)是一种小巧的组件,用于显示计数、提示或标识信息。本文将详细介绍 Bootstrap 标签的用法、样式和示例。 B…

Hadoop 面试题(四)

1. 简述Hadoop节点的动态上线下线的大概操作 &#xff1f; 在Hadoop集群中&#xff0c;节点的动态上下线指的是在不停止整个集群服务的情况下&#xff0c;添加或移除节点。这种能力对于维护和扩展集群非常重要。以下是Hadoop节点动态上线下线的大概操作步骤&#xff1a; 动态…

百度地图3d区域掩膜,最常见通用的大屏地图展现形式

需求及效果 原本项目使用的是百度地图3.0,也就是2d版本的那个地图,客户不满意觉得不够好看,让把地图改成3d的,但是我们因为另外的系统用的都是百度地图,为了保持统一只能用百度地图做 经过3天的努力,最后我终于把这个效果实现了,效果如下: 如何引用GL版本 为了实现…

解决vmware “处理器不支持 XSAVE。无法打开此虚拟机的电源。“

1,打开windows 10-11 的 虚拟机平台 选择 “开始”&#xff0c;输入“Windows 功能”&#xff0c;然后从结果列表中选择“打开或关闭 Windows 功能 ”。 在刚刚打开的 “Windows 功能”窗口中&#xff0c;找到“虚拟机平台 ”并将其选中。 选择“确定”。 可能需要重启电脑。…

开发中遇到的一个bug

遇到的报错信息是这样的&#xff1a; java: Annotation processing is not supported for module cycles. Please ensure that all modules from cycle [hm-api,hm-common,hm-service] are excluded from annotation processing 翻译过来就是存在循环引用的情况&#xff0c;导…

《Windows API每日一练》5.3 字符消息

在本章前面讲过&#xff0c;通过转义状态信息可把击键消息转换为字符消息。并且提到&#xff0c;仅仅利用转义状态信息是不够的。还必须知道与国家/地区相关的键盘配置。其实不必担心这个问题。Windows程序主程序中的消息循环可以完美的解决这个问题。 while (GetMessage (&am…

Spring中的ContextPath总结

Spring中的ContextPath总结 大家好&#xff0c;我是免费搭建查券返利机器人省钱赚佣金就用微赚淘客系统3.0的小编&#xff0c;也是冬天不穿秋裤&#xff0c;天冷也要风度的程序猿&#xff01; 1. ContextPath的概念 在Spring中&#xff0c;ContextPath是指Web应用程序的上下文…

不懂就问,开通小程序地理位置接口有那么难吗?

小程序地理位置接口有什么功能&#xff1f; 若提审后被驳回&#xff0c;理由是“当前提审小程序代码包中地理位置相关接口( chooseAddress、getLocation )暂未开通&#xff0c;建议完成接口开通后或移除接口相关内容后再进行后续版本提审”&#xff0c;那么遇到这种情况&#x…

29.Netty进阶-黏包半包

黏包现象 服务端代码 package com.xkj.nian;import io.netty.bootstrap.ServerBootstrap; import io.netty.channel.ChannelFuture; import io.netty.channel.ChannelInitializer; import io.netty.channel.nio.NioEventLoopGroup; import io.netty.channel.socket.SocketCha…

USB2.0网卡安装驱动

有三种安装方式&#xff1a; 驱动精灵驱动总裁USB2.0网卡自带安装程序 前两种很简单&#xff0c;下载驱动精灵或者驱动总裁&#xff0c;然后检测本地硬件&#xff0c;安装相应驱动。 本文重点要介绍的是第三种&#xff0c;利用USB2.0网卡自带的安装程序。有的时候驱动精灵或…

Github 2024-06-22Rust开源项目日报 Top10

根据Github Trendings的统计,今日(2024-06-22统计)共有10个项目上榜。根据开发语言中项目的数量,汇总情况如下: 开发语言项目数量Rust项目10Dart项目1Move项目1TypeScript项目1RustDesk: 用Rust编写的开源远程桌面软件 创建周期:1218 天开发语言:Rust, Dart协议类型:GNU …

Redis—Hash数据类型及其常用命令详解

文章目录 Redis概述Hash类型Hash类型常用命令1 HSET&#xff1a;添加或者修改hash类型key的field的值2 HGET &#xff1a;获取一个hash类型key的field的值3 HMSET&#xff1a;批量添加多个hash类型key的field的值4 HMGET&#xff1a;批量获取多个hash类型key的field的值5 HGETA…

华为DCN技术:M-LAG

M-LAG&#xff08;Multichassis Link Aggregation Group&#xff09;即跨设备链路聚合组&#xff0c;是一种实现跨设备链路聚合的机制。M-LAG主要应用于普通以太网络、VXLAN和IP网络的双归接入&#xff0c;可以起到负载分担或备份保护的作用。相较于另一种常见的可靠性接入技术…

第二十七篇——通信趋势:5G和IOT的商机在哪里?

目录 一、背景介绍二、思路&方案三、过程1.思维导图2.文章中经典的句子理解3.学习之后对于投资市场的理解4.通过这篇文章结合我知道的东西我能想到什么&#xff1f; 四、总结五、升华 一、背景介绍 借势的重要性&#xff0c;但是要做到借势&#xff0c;得先看到&#xff0…

区块链技术:金融市场监管的新篇章

一、引言 随着金融科技的迅猛发展&#xff0c;区块链技术作为其中的佼佼者&#xff0c;正逐渐改变着金融市场的格局。在金融市场监管领域&#xff0c;区块链技术以其独特的优势&#xff0c;为监管机构提供了新的监管思路和手段。本文将深入探讨区块链技术在金融市场监管中的作用…

精通Java中的线程同步与互斥

精通Java中的线程同步与互斥 大家好&#xff0c;我是免费搭建查券返利机器人省钱赚佣金就用微赚淘客系统3.0的小编&#xff0c;也是冬天不穿秋裤&#xff0c;天冷也要风度的程序猿&#xff01; 在多线程编程中&#xff0c;线程同步与互斥是非常重要的概念。Java作为一种强大的…