2024-01-17:lc的30. 串联所有单词的子串
2024-01-17:用go语言,给定一个字符串 s 和一个字符串数组 words。 words 中所有字符串 长度相同。
s 中的 串联子串 是指一个包含 words 中所有字符串以任意顺序排列连接起来的子串。
例如,如果 words = ["ab","cd","ef"],
那么 "abcdef", "abefcd","cdabef",
"cdefab","efabcd", 和 "efcdab" 都是串联子串,
"acdbef" 不是串联子串,因为他不是任何 words 排列的连接。
返回所有串联字串在 s 中的开始索引。
你可以以 任意顺序 返回答案。
1 <= s.length <= 10^4,
1 <= words.length <= 5000,
1 <= words[i].length <= 30。
words[i] 和 s 由小写英文字母组成。
输入:s = "barfoothefoobarman", words = ["foo","bar"]。
输出:[0,9]。
来自lc的30. 串联所有单词的子串。
答案2024-01-17:
来自左程云。
大体过程如下:
定义一些常量和变量,包括
BASE和MAXN,以及存储结果的切片ans。实现
hashValue函数,用于计算字符串的哈希值。这里使用一个基于索引的简单哈希函数将字符串映射为一个唯一的整数。实现
buildHash函数,用于构建字符串的前缀哈希数组。通过动态规划的方式计算每个位置的哈希值。实现
hashValueRange函数,用于计算子串的哈希值。利用前缀哈希数组,根据子串的起始和结束位置计算哈希值。创建一个哈希表
mapCount用于存储words中每个单词的出现次数。构建字符串
s的前缀哈希数组hash。创建一个数组
pow,用于存储 BASE 的幂次方,便于后续计算子串的哈希值。创建一个滑动窗口
window,用于记录当前窗口中每个单词出现的次数。循环遍历
s中每个起始位置的可能性(即从 0 到wordLen-1)。在每个起始位置,初始化一个变量
debt用于记录还需要凑齐的单词数。在每个起始位置,遍历
words中的单词,依次将其添加到窗口中,并更新debt的值。如果
debt等于 0,表示窗口中已经包含了所有words中的单词,则将当前起始位置加入结果数组ans中。对于每个起始位置,向右移动窗口,同时更新窗口中单词的出现次数。
检查窗口中的哈希值和单词出现次数是否符合要求,如果符合则将当前起始位置加入结果数组
ans中。清空滑动窗口
window。返回结果数组
ans。
总的时间复杂度:O(n * m * k),其中 n 是字符串 s 的长度,m 是 words 的长度,k 是单词的平均长度。
总的额外空间复杂度:O(n),其中 n 是字符串 s 的长度,主要用于存储哈希表、前缀哈希数组和结果数组。
go完整代码如下:
package main
import (
"fmt"
)
var BASE = 499
var MAXN = 10001
func hashValue(str string) int64 {
if str == "" {
return 0
}
n := len(str)
ans := int64(str[0]-'a') + 1
for j := 1; j < n; j++ {
ans = ans*int64(BASE) + int64(str[j]-'a') + 1
}
return ans
}
func buildHash(str string) []int64 {
hash := make([]int64, len(str))
hash[0] = int64(str[0]-'a') + 1
for j := 1; j < len(str); j++ {
hash[j] = hash[j-1]*int64(BASE) + int64(str[j]-'a') + 1
}
return hash
}
func hashValueRange(l, r int, hash []int64, pow []int64) int64 {
ans := hash[r-1]
if l > 0 {
ans -= hash[l-1] * pow[r-l]
}
return ans
}
func findSubstring(s string, words []string) []int {
var ans []int
if len(s) == 0 || len(words) == 0 {
return ans
}
wordLen := len(words[0])
wordNum := len(words)
allLen := wordLen * wordNum
mapCount := make(map[int64]int)
for _, key := range words {
v := hashValue(key)
mapCount[v]++
}
hash := buildHash(s)
pow := make([]int64, MAXN)
pow[0] = 1
for j := 1; j < MAXN; j++ {
pow[j] = pow[j-1] * int64(BASE)
}
window := make(map[int64]int)
for init := 0; init < wordLen && init+allLen <= len(s); init++ {
debt := wordNum
for l, r, part := init, init+wordLen, 0; part < wordNum; l += wordLen {
cur := hashValueRange(l, r, hash, pow)
window[cur]++
if window[cur] <= mapCount[cur] {
debt--
}
r += wordLen
part++
}
if debt == 0 {
ans = append(ans, init)
}
for l1, r1, l2, r2 := init, init+wordLen, init+allLen, init+allLen+wordLen; r2 <= len(s); l1, r1, l2, r2 = l1+wordLen, r1+wordLen, l2+wordLen, r2+wordLen {
out := hashValueRange(l1, r1, hash, pow)
in := hashValueRange(l2, r2, hash, pow)
window[out]--
if window[out] < mapCount[out] {
debt++
}
window[in]++
if window[in] <= mapCount[in] {
debt--
}
if debt == 0 {
ans = append(ans, r1)
}
}
for key := range window {
delete(window, key)
}
}
return ans
}
func main() {
s := "barfoothefoobarman"
words := []string{"foo", "bar"}
result := findSubstring(s, words)
fmt.Println(result)
}

2024-01-17:lc的30. 串联所有单词的子串的更多相关文章
- Java实现 LeetCode 30 串联所有单词的子串
30. 串联所有单词的子串 给定一个字符串 s 和一些长度相同的单词 words.找出 s 中恰好可以由 words 中所有单词串联形成的子串的起始位置. 注意子串要与 words 中的单词完全匹配, ...
- leetcode 30. 串联所有单词的子串 【时间击败 90.28%】 【内存击败 97.44%】
这道题让我从早做到晚-3--- 设len=words[0].length(). 一开始我按照words的顺序扩大区间,发现这样就依赖words的顺序.之后改成遍历s的所有长度为len*words.le ...
- [LeetCode] 30. 串联所有单词的子串
题目链接: https://leetcode-cn.com/problems/substring-with-concatenation-of-all-words/ 题目描述: 给定一个字符串 s 和一 ...
- Leetcode 30 串联所有单词的子串 滑动窗口+map
见注释.滑动窗口还是好用. class Solution { public: vector<int> findSubstring(string s, vector<string> ...
- [LeetCode] 30. Substring with Concatenation of All Words 串联所有单词的子串
You are given a string, s, and a list of words, words, that are all of the same length. Find all sta ...
- [LeetCode] Substring with Concatenation of All Words 串联所有单词的子串
You are given a string, s, and a list of words, words, that are all of the same length. Find all sta ...
- 【LeetCode-面试算法经典-Java实现】【030-Substring with Concatenation of All Words(串联全部单词的子串)】
[030-Substring with Concatenation of All Words(串联全部单词的子串)] [LeetCode-面试算法经典-Java实现][全部题目文件夹索引] 原题 Yo ...
- 【LeetCode 30】串联所有单词的子串
题目链接 [题解] 开个字典树记录下所有的单词. 然后注意题目的已知条件 每个单词的长度都是一样的. 这就说明不会出现某个字符串是另外一个字符串的前缀的情况(除非相同). 所以可以贪心地匹配(遇到什么 ...
- leetcode30 串联所有单词的子串
先对words中的单词排列组合,然后对s滑窗操作:部分样例超时,代码如下: class Solution { public: vector<int> findSubstring(strin ...
- 2019/01/17 基于windows使用fabric将gitlab的文件远程同步到服务器(git)
觉得django项目把本地更新push到gitlab,再执行fabric脚本从gitlab更新服务器项目挺方便的,当然从本地直接到服务器就比较灵活. 2019/01/17 基于windows使用fab ...
随机推荐
- 激发创新,助力研究:CogVLM,强大且开源的视觉语言模型亮相
激发创新,助力研究:CogVLM,强大且开源的视觉语言模型亮相 CogVLM 是一个强大的开源视觉语言模型(VLM).CogVLM-17B 拥有 100 亿视觉参数和 70 亿语言参数. CogVLM ...
- H.264中的帧
导言 高级视频编码 (AVC) 也称为 H.264,是使用最广泛的视频压缩标准.它与所有主要的流式传输协议和容器格式兼容. 当我们使用播放器播放一个视频时,通常会经过:解协议,解封装,音视频解码,音视 ...
- wps表格怎么打印选中区域的内容?
打印选中区域的内容,您可以按照以下步骤进行操作: 选择要打印的区域 打开 WPS 表格,在工作表中选择您希望打印的区域.您可以拖动鼠标或使用键盘中的方向键来选择单元格. 设置打印区域 一旦您选中了需要 ...
- Git恢复删除的文件,一行命令就可以啦~
情况一:删除或者修改了某个文件,但是没有add # 单个 git checkout filename # 多个 git checkout . 情况二:删除或者修改了某个文件,已经add,但是没有com ...
- 三种方式查询三级分类Tree
话不多说,直接上代码 方式一:for循环嵌套一下 /** * 查询三级分类 * * @return */ @Override public List<GoodsType> findNode ...
- SpringBoot项目整合微信登录
一.开通微信登录 去微信开发者平台 1.注册 2.邮箱激活 3.完善开发者资料 4.开发者资质认证 准备营业执照,1-2个工作日审批.300元 5.创建网站应用 6.提交审核,7个工作日审批 7.熟悉 ...
- AI量化策略会:可以直接上实盘的策略构建方法
一年一度的培训虽晚但到,这是BigQuant与大家走过的第五个培训年头,在过去的四年里看到很多学员的成长和蜕变,从一开始的懵懂无知,到现在对深度学习的信手拈来,BigQuant与各位学员们一样都收获颇 ...
- flask自带的异常抛出函数abort
flask中有一个abort函数,可以用于快捷的抛出异常, 但是只能抛出标准的HTTP状态码,不能乱设置HTPP状态码,比如666.777这种. from flask import abort @ap ...
- 数字孪生技术结合GIS系统能在农业领域作出什么改变?
数字孪生技术和地理信息系统(GIS)是两个独立但高度互补的领域,它们的结合在农业领域具有巨大的潜力,可以带来巨大的改变.在这篇文章中,我们将讨论数字孪生技术和GIS系统如何协同作用,为农业带来创新和可 ...
- Plant-Earth-wp
Earth 信息收集 开放了80,443 只能访问到443,试了试msf里面frado的远古rce都不成功.然后注意到有域名解析 添加到hosts里面再访问,当前页面有几串密文,经尝试在message ...