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完整代码如下:

package main

import (
"fmt"
"math/rand"
) func howMany1(str1 string, str2 string, k int) int {
n := len(str1)
m := len(str2)
if n < m {
return 0
}
s := []rune(str1)
p := []rune(str2)
ans := 0
for i := 0; i <= n-m; i++ {
if diffLessK1(s, i, p, k, m) {
ans++
}
}
return ans
} func diffLessK1(s []rune, i int, p []rune, k int, m int) bool {
diff := 0
for j := 0; j < m; j++ {
if s[i+j] != p[j] {
diff++
}
}
return diff <= k
} const MAXN = 100001
const base = 1000000007 var pow []int64 = make([]int64, MAXN)
var hashs []int64 = make([]int64, MAXN)
var hashp []int64 = make([]int64, MAXN) func buildHash(s []rune, n int, p []rune, m int) {
hashs[0] = int64(s[0] - 'a' + 1)
for j := 1; j < n; j++ {
hashs[j] = hashs[j-1]*base + int64(s[j]-'a'+1)
}
hashp[0] = int64(p[0] - 'a' + 1)
for j := 1; j < m; j++ {
hashp[j] = hashp[j-1]*base + int64(p[j]-'a'+1)
}
} func howMany2(str1 string, str2 string, k int) int {
n := len(str1)
m := len(str2)
if n < m {
return 0
}
s := []rune(str1)
p := []rune(str2)
buildHash(s, n, p, m)
ans := 0
for i := 0; i <= n-m; i++ {
if diffLessK2(i, i+m-1, 0, m-1, k) {
ans++
}
}
return ans
} func diffLessK2(l1 int, r1 int, l2 int, r2 int, k int) bool {
diff := 0
for l1 <= r1 && diff <= k {
l, r := 1, r1-l1+1
len := 0
for l <= r {
m := (l + r) / 2
if ok(l1, l2, m) {
len = m
l = m + 1
} else {
r = m - 1
}
}
if l1+len <= r1 {
diff++
}
l1 += len + 1
l2 += len + 1
}
return diff <= k
} func ok(l1 int, l2 int, len int) bool {
return hash(hashs, l1, l1+len-1) == hash(hashp, l2, l2+len-1)
} func hash(hash []int64, l int, r int) int64 {
ans := hash[r]
if l == 0 {
return ans
}
ans -= hash[l-1] * pow[r-l+1]
return ans
} func init() {
pow[0] = 1
for j := 1; j < MAXN; j++ {
pow[j] = pow[j-1] * base
}
} // 生成随机子串
func randomString(len int, rangeNum int) string {
b := make([]byte, len)
for i := 0; i < len; i++ {
b[i] = byte(rand.Intn(rangeNum) + 'a')
}
return string(b)
} func main() {
N := 100
M := 50
K := 10
// a b c
// R =4 abcd
R := 3
testTimes := 10000
fmt.Println("测试开始")
for i := 0; i < testTimes; i++ {
n := rand.Intn(N) + 1
m := rand.Intn(M) + 1
k := rand.Intn(K)
str1 := randomString(n, R)
str2 := randomString(m, R)
ans1 := howMany1(str1, str2, k)
ans2 := howMany2(str1, str2, k)
if ans1 != ans2 {
fmt.Println("出错了!")
}
}
fmt.Println("测试结束")
}

2023-11-11:用go语言,字符串哈希+二分的例题。 给定长为 n 的源串 s,以及长度为 m 的模式串 p, 要求查找源串中有多少子串与模式串匹配, s‘ 与 s 匹配,当且仅当 s‘ 与 s的更多相关文章

  1. 【CodeForces】961 F. k-substrings 字符串哈希+二分

    [题目]F. k-substrings [题意]给定长度为n的串S,对于S的每个k-子串$s_ks_{k+1}...s_{n-k+1},k\in[1,\left \lceil \frac{n}{2} ...

  2. C语言字符串之无重复字符的最长子串

    题目描述 给定一个字符串,请你找出其中不含有重复字符的 最长子串 的长度. 示例 输入: "abcabcbb" 输出: 解释: 因为无重复字符的最长子串是 . 输入: " ...

  3. C语言字符串操作总结大全(超详细)

    本篇文章是对C语言字符串操作进行了详细的总结分析,需要的朋友参考下 1)字符串操作  strcpy(p, p1) 复制字符串  strncpy(p, p1, n) 复制指定长度字符串  strcat( ...

  4. C语言字符串与数字相互转换

    在C/C++语言中没有专门的字符串变量,通常用字符数组来存放字符串.字符串是以“\0”作为结束符.C/C++提供了丰富的字符串处理函数,下面列出了几个最常用的函数. ● 字符串输出函数puts. ● ...

  5. C 语言 字符串命令 strstr()的用法 实现将原字符串以分割串分割输出

    C 语言 字符串命令 strstr()的用法 实现将原字符串以分割串分割输出 strstr() 命令是在原字符串中查找指定的字符串第一次出现的地址,用这个特性可以实现字符的分割,判断是否包涵等功能: ...

  6. 【转】C语言字符串与数字相互转换

    在C/C++语言中没有专门的字符串变量,通常用字符数组来存放字符串.字符串是以“\0”作为结束符.C/C++提供了丰富的字符串处理函数,下面列出了几个最常用的函数. ● 字符串输出函数puts. ● ...

  7. C.【转】C语言字符串与数字相互转换

    1.gcvt 把浮点数转成字符串 - CSDN博客.html(https://blog.csdn.net/dxuehui/article/details/52791412) 1.1. 函数名: gcv ...

  8. Strsafe.h:更安全的C语言字符串处理函数

    原文出处:Strsafe.h: Safer String Handling in C 作者:Michael Howard 编译:王凌峰 在微软公司举行的Microsoft Windows Securi ...

  9. 零基础学习C语言字符串操作总结大全

    本篇文章是对C语言字符串操作进行了详细的总结分析,需要的朋友参考下 1)字符串操作 strcpy(p, p1) 复制字符串 strncpy(p, p1, n) 复制指定长度字符串 strcat(p, ...

  10. C语言字符串操作总结大全

    1)字符串操作 strcpy(p, p1)  复制字符串  函数原型strncpy(p, p1, n)   复制指定长度字符串  函数原型strcat(p, p1)   附加字符串  函数原型strn ...

随机推荐

  1. linux top中 VSS,RSS,PSS,USS 4个字段的解读

    参考文章:linux中top命令 VSS,RSS,PSS,USS 四个内存字段的解读

  2. 【go语言】2.4.2 自定义包的创建和使用

    在 Go 中,任何一个目录都可以被视为一个包.创建自定义包的基本步骤是: 新建一个目录,用于存放包的源文件. 在新建的目录中编写 Go 代码,代码的第一行应该是 package 包名. 使用 impo ...

  3. 浅谈php伪协议的运用

    浅谈php伪协议的运用 (133条消息) PHP Filter伪协议Trick总结_php伪协议rot13的用法_swtre33的博客-CSDN博客 php死亡exit()绕过 - xiaolong' ...

  4. pycharm: 注释自动生成

    解决方案如下

  5. 王道oj/problem17

    网址:http:oj.lgwenda.com/problem17 思路:指针其实就是存储地址的一个空间,LinkList=LNode* 代码: #define _CRT_SECURE_NO_WARNI ...

  6. Vue3 路由优化,使页面初次渲染效率翻倍

    3996 条路由? addRoute函数用了大约1s才执行完毕.通过观察,发现居然有3996条路由记录. 可是项目并没有这么多的页面啊~ 重复路由 let routes: Array<Route ...

  7. 一文详解自然语言处理两大任务与代码实战:NLU与NLG

    自然语言处理(NLP)涵盖了从基础理论到实际应用的广泛领域,本文深入探讨了NLP的关键概念,包括词向量.文本预处理.自然语言理解与生成.统计与规则驱动方法等,为读者提供了全面而深入的视角. 作者 Te ...

  8. Deno 中使用 @typescript/vfs 生成 DTS 文件

    背景 前段时间开源的 STC 工具,这是一个将 OpenApi 规范的 Swagger/Apifox 文档转换成代码的工具.可以在上一篇(<OpenApi(Swagger)快速转换成 TypeS ...

  9. 震惊!CSS 也能实现碰撞检测?

    本文,我们将一起学习,使用纯 CSS,实现如下所示的动画效果: 上面的动画效果,非常有意思,核心有两点: 小球随机做 X.Y 方向的直线运动,并且能够实现碰撞到边界的时候,实现反弹效果 小球在碰撞边界 ...

  10. 论文解读(IW-Fit)《Better Fine-Tuning via Instance Weighting for Text Classification》

    Note:[ wechat:Y466551 | 可加勿骚扰,付费咨询 ] 论文信息 论文标题:Better Fine-Tuning via Instance Weighting for Text Cl ...