【滚动哈希 二分查找】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,一经查实,立即删除!

相关文章

基于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;来看看公司内外采购交易所对…

百度地图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;导…

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

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

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;为监管机构提供了新的监管思路和手段。本文将深入探讨区块链技术在金融市场监管中的作用…

【分布式系列】分布式锁timeout了怎么办?

&#x1f49d;&#x1f49d;&#x1f49d;欢迎来到我的博客&#xff0c;很高兴能够在这里和您见面&#xff01;希望您在这里可以感受到一份轻松愉快的氛围&#xff0c;不仅可以获得有趣的内容和知识&#xff0c;也可以畅所欲言、分享您的想法和见解。 推荐:kwan 的首页,持续学…

XSS漏洞—XSS平台搭建与打cookie

一、跨站脚本攻击漏洞接收平台 推荐两个&#xff1a; 1&#xff09;xsser &#xff1a; XSS平台 - &#xff08;支持http/https&#xff09;XSS Platform 2&#xff09;蓝莲花 &#xff1a;GitHub - firesunCN/BlueLotus_XSSReceiver xsser&#xff1a; BlueLotus&#xff…

SM3在线计算工具

SM3是中华人民共和国政府采用的一种密码散列函数标准&#xff0c;由国家密码管理局于2010年12月17日发布。相关标准为“GM/T 0004-2012 《SM3密码杂凑算法》”。 在商用密码体系中&#xff0c;SM3主要用于数字签名及验证、消息认证码生成及验证、随机数生成等&#xff0c;其算法…

RPM 打包入门(基于openEuler)

主要参考内容&#xff08;均为官方文档&#xff09;&#xff1a; https://rpm-packaging-guide.github.io/#building-rpms https://docs.redhat.com/zh_hans/documentation/red_hat_enterprise_linux/8/html/packaging_and_distributing_software/introduction-to-rpm_packagin…

WPF文本绑定显示格式StringFormat设置-特殊格式时间日期和多数据绑定

WPF文本绑定显示格式StringFormat设置 特殊格式设置日期/时间使用系统默认样式自定义格式&#xff1a; 绑定多个属性&#xff08;多重绑定&#xff09;多重绑定中的特殊字符示例&#xff1a; 特殊格式设置 在Textblock等文本控件中&#xff0c;我们经常要显示一些日期和时间&a…

【R语言】地理探测器模拟及分析(Geographical detector)

地理探测器模拟及分析 1. 写在前面2. R语言实现2.1 数据导入2.2 确定数据离散化的最优方法与最优分类2.3 分异及因子探测器&#xff08;factor detector&#xff09;2.4 生态探测器&#xff08;ecological detector&#xff09;2.5 交互因子探测器&#xff08;interaction dete…

Leetcode3184. 构成整天的下标对数目 I

Every day a Leetcode 题目来源&#xff1a;3184. 构成整天的下标对数目 I 解法1&#xff1a;遍历 统计满足 i < j 且 hours[i] hours[j] 构成整天的下标对 i, j 的数目。 构成整天的条件&#xff1a;(hours[i] hours[j]) % 24 0。 代码&#xff1a; /** lc applee…