2023-11-11:用 go 语言,字符串哈希 + 二分的例题。 给定长为 n 的源串 s,以及长度为 m 的模式串 p, 要求查找源串中有多少子串与模式串匹配, s‘ 与 s 匹配,当且仅当 s‘ 与 s
2023-11-11:用 go 语言,字符串哈希+二分的例题。
给定长为 n 的源串 s,以及长度为 m 的模式串 p,
要求查找源串中有多少子串与模式串匹配,
s' 与 s 匹配,当且仅当 s' 与 s 长度相同,且最多有 k 个位置字符不同。
其中 1 <= n, m <= 10^6,0 <= k <= 5。
来自左程云。
答案 2023-11-11:
go 代码用灵捷 3.5 编写。
大体过程如下:
算法 1:
遍历源串 s 中所有长度为 m 的子串,判断子串与模式串的不同字符数量是否小于等于 k,若是,将统计的子串数量加 1。具体地:
1.首先计算源串 s 的长度 n 和模式串 p 的长度 m。
2.若 n < m,则返回 0。
3.将源串 s 和模式串 p 转换为 rune 类型的切片,方便进行字符比较。
4.遍历源串 s 中所有长度为 m 的子串,判断子串与模式串的不同字符数量是否小于等于 k,若是,将统计的子串数量加 1。
5.返回统计的子串数量。
算法 2:
计算源串 s 的哈希值和模式串 p 的哈希值,然后遍历源串 s 中所有长度为 m 的子串,判断子串与模式串的哈希值是否相等,若是则比较子串与模式串的每个字符是否相同,最多允许 k 个字符不同。具体地:
1.首先计算源串 s 的长度 n 和模式串 p 的长度 m。
2.若 n < m,则返回 0。
3.将源串 s 和模式串 p 转换为 rune 类型的切片,方便进行哈希操作。
4.计算源串 s 的哈希值和模式串 p 的哈希值,分别保存在 hashs 和 hashp 数组中。
5.遍历源串 s 中所有长度为 m 的子串,判断子串与模式串的哈希值是否相等,若是则比较子串与模式串的每个字符是否相同,最多允许 k 个字符不同。
6.比较子串与模式串的每个字符是否相同,最多允许 k 个字符不同的具体实现:遍历子串中每个字符,二分查找在模式串中与该字符相同的位置,若找到了,则比较子串和模式串中该位置的字符是否相同,否则允许 k 的值加 1。如果 k 的值大于了允许的最大值,那么返回 false。
7.返回 true。
时间复杂度和空间复杂度分析:
算法 1:
时间复杂度:代码中主要的时间复杂度来源于遍历源串 s 中所有长度为 m 的子串,遍历次数为 O(n-m+1),每次遍历需要比较 m 个字符,因此总的时间复杂度为 O((n-m+1)*m)。由于 n 和 m 的值均不超过 10^6,因此算法 1 的总的时间复杂度为 O(10^12),在实际情况中运算速度较慢。
空间复杂度:算法 1 只需要占用 O(n+m) 的额外空间,用于存储源串 s 和模式串 p。
算法 2:
时间复杂度:代码中主要的时间复杂度来源于计算源串 s 和模式串 p 的哈希值,以及遍历源串 s 中所有长度为 m 的子串,遍历次数为 O(n-m+1),每次需要计算哈希值和比较 m 个字符,因此总的时间复杂度为 O((n-m+1)*(m+logn))。由于 n 和 m 的值均不超过 10^6,因此算法 2 的总的时间复杂度为 O(10^12),与算法 1 的时间复杂度相同,但实际速度更快。
空间复杂度:算法 2 需要占用 O(n+m) 的额外空间,用于存储源串 s 和模式串 p 的哈希值,以及 O(n) 的额外空间,用于存储哈希值计算过程中的幂 base^i(i<=n)。
总结:
算法 1 和算法 2 的时间复杂度都为 O(10^12),但实际运算速度可能存在很大的差异,具体取决于实现过程中的细节。在实际应用中,算法 2 比算法 1 更为常用,因为哈希算法能够在较快的时间内完成字符串的比较。
go 完整代码如下:
版权声明: 本文为 InfoQ 作者【福大大架构师每日一题】的原创文章。
原文链接:【http://xie.infoq.cn/article/43582eb44c8df4fd17dbf5e44】。
本文遵守【CC-BY 4.0】协议,转载请保留原文出处及本版权声明。
评论