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. clickhouse 与 zookeeper

    目录 clickhouse 设置中的 zookeeper 配置 参数说明 配置示例 [预发生产] ClickHouse Keeper 四字母命令 clickhouse 设置中的 zookeeper 配 ...

  2. 【go语言】2.1.1 变量,常量和数据类型

    Go 语言中,变量是存储数据的基本单位,常量则是固定不变的数据.每个变量和常量都有其对应的数据类型. 变量 在 Go 语言中,你可以使用 var 关键字来声明一个变量: var name string ...

  3. Jenkins服务开机自启动

    最近因为护网行动,每天都要对服务器进行开.关机操作.为了省事儿,对Jenkins服务进行开机自动启动服务改造.实现如下: 1. 通过chkconfig --list命令列出系统中已安装的服务及其启动状 ...

  4. CF1787E The Harmonization of XOR 题解

    CF1787E The Harmonization of XOR 题目大意 给定 \(n\) 个数 \([1, 2, 3, \cdots, n]\) 和两个正整数 \(k\) 和 \(x\). 将这些 ...

  5. AI绘画StableDiffusion美女实操教程:斗破苍穹-小医仙

    之前分享过StableDiffusion的入门到精通教程:AI绘画:Stable Diffusion 终极炼丹宝典:从入门到精通 但是还有人就问:安装是安装好了,可是为什么生成的图片和你生成的图片差距 ...

  6. MindSponge分子动力学模拟——计算单点能(2023.08)

    技术背景 在前面的几篇文章中,我们分别介绍了MindSponge的软件架构.MindSponge的安装与使用和如何在MindSponge中定义一个分子系统.那么就像深度学习中的损失函数,或者目标函数, ...

  7. 拼多多根据ID取商品详情 API 返回值说明

    ​ item_get-根据ID取商品详情 注册开通 pinduoduo.item_get 公共参数 名称 类型 必须 描述 key String 是 调用key(必须以GET方式拼接在URL中) se ...

  8. WPF 自定义窗体(一)

    .Net默认的窗体样式只有四种:None.SingleBorderWindow.ThreeDBorderWindow.ToolWindow,都比较"丑".而很多时候,我们希望自定义 ...

  9. Markdown初识

    1.标题 一级标题 ctrl+1......六级标题 ctrl+6 2.字体 加粗 ctrl+B 斜体 ctrl+I 下划线 ctrl+ U 3.引用 大于号加任意键 4.分割线 "---& ...

  10. 数据库sql中处理时间冲突问题

    数据库现有数据其中两列: s - 开始时间, e - 结束时间. 在新插入数据s', e'之前需要判断两个时间之间是否有重合 因为使用mybatis-plus的缘故, 结论都使用s或e在符号前面. 1 ...