Rabin-Karp 算法在滚动哈希中的应用:重复子串查找
字数 924 2025-11-01 15:29:06
Rabin-Karp 算法在滚动哈希中的应用:重复子串查找
题目描述:
给定一个字符串 s,判断 s 中是否存在长度至少为 2 的重复子串。如果存在,返回 true;否则返回 false。注意:重复子串可以重叠,例如 "aba" 中 "a" 重复出现,但长度不足 2,因此返回 false;而 "abab" 中 "ab" 重复出现,返回 true。
解题过程:
-
问题分析
暴力解法是枚举所有长度 L(从 2 到 n/2)的子串,检查每个长度为 L 的子串是否重复出现,但时间复杂度为 O(n³)。Rabin-Karp 算法通过滚动哈希将时间复杂度优化至 O(n²)。 -
滚动哈希原理
将字符串视为一个多进制数(例如基数为 26,假设只含小写字母),计算子串的哈希值。当窗口向右滑动时,新哈希值可通过旧哈希值快速计算:
新哈希值 = (旧哈希值 - 移除字符的贡献) * 基数 + 新字符的贡献
为避免溢出,需对一个大素数取模(如 10⁹+7)。 -
算法步骤
- 遍历可能的子串长度 L(从 1 到 n/2):
- 初始化一个空哈希集合,存储已出现的子串哈希值。
- 计算前 L 个字符的哈希值
hash_old。 - 从下标 0 开始滑动长度为 L 的窗口:
- 若当前
hash_old已在集合中出现,说明找到重复子串,返回 true。 - 否则将
hash_old加入集合。 - 若窗口未到末尾,计算下一个窗口的哈希值:
hash_new = (hash_old - s[start] * base^(L-1)) * base + s[start+L]
注意:需预处理base^(L-1)的模幂结果。
- 若当前
- 若所有 L 均无重复,返回 false。
- 遍历可能的子串长度 L(从 1 到 n/2):
-
冲突处理
哈希可能冲突,因此当哈希值匹配时,需用直接比较子串内容确认是否真重复(避免误判)。 -
复杂度分析
外层遍历 L 为 O(n),内层滑动窗口为 O(n),整体 O(n²)。空间复杂度 O(n) 存储哈希集合。
示例:s = "abab"
- L=2 时,窗口 "ab" 哈希值加入集合;滑动到 "ba",哈希值不同;再滑动到 "ab",哈希值在集合中存在,检查内容后确认重复,返回 true。