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 ...
随机推荐
- Educational Codeforces Round 104 (Rated for Div. 2) A~E题解
写在前边 链接:Educational Codeforces Round 104 (Rated for Div. 2) A. Arena 链接:A题链接 题目大意: 给定一个长度为\(n\)的数组,表 ...
- R数据分析:集成学习方法之随机生存森林的原理和做法,实例解析
很久很久以前给大家写过决策树,非常简单明了的算法.今天给大家写随机(生存)森林,随机森林是集成了很多个决策数的集成模型.像随机森林这样将很多个基本学习器集合起来形成一个更加强大的学习器的这么一种集成思 ...
- 一个NET8 AOT编译的辅助项目,让你的任何可执行应用快速部署为服务
不知道大家有没有和小编一样,很多时候想将自己的一些应用转为服务运行,比如一些控制台应用或者.NET Core应用,但是又不想重新编码,把他们转为服务,本文将给大家提供些我使用过的方法,并提供一个基于N ...
- dbeaver软件的使用
dbeaver软件的使用 一.dbeaver简介: dbeaver是免费和开源(GPL)为开发人员和数据库管理员通用数据库工具. DBeaver [1] 是一个通用的数据库管理工具和 SQL 客户端, ...
- 赛意SMOM和金蝶云星空单据接口对接
赛意SMOM和金蝶云星空单据接口对接 数据源系统:金蝶云星空 金蝶K/3Cloud在总结百万家客户管理最佳实践的基础上,提供了标准的管理模式:通过标准的业务架构:多会计准则.多币别.多地点.多组织.多 ...
- 循环依赖导致编译或者服务启动报错问题:The dependencies of some of the beans in the application context form a cycle
错误如图: 我的是服务器启动服务时报错: ***************************APPLICATION FAILED TO START************************* ...
- [HAOI2018] 字串覆盖
[HAOI2018]字串覆盖 题目描述 小C对字符串颇有研究,他觉得传统的字符串匹配太无聊了,于是他想到了这 样一个问题. 对于两个长度为n的串A, B, 小C每次会给出给出4个参数s, t, l, ...
- gho、wim、esd的区别
本文介绍的仅仅是压缩格式上的区别,并不是一些个体错误理解的 "GHOST 镜像 = 带驱动的快速装机镜像",实际 ESD 格式和 WIM 格式,也一样是可以集成驱动做成二次封装的快 ...
- ElasticSearch查询数据、全文检索、补全提示、拼写纠错
https://www.elastic.co/guide/en/elasticsearch/reference/6.8/search.html https://www.elastic.co/guide ...
- 华企盾DSC客户端连不上服务器(客户端在回收站)
解决方法:确保该计算机在CLIENT表recyclebin列中的值为False,最好把所有计算机都改成False,改好后重启DSC服务器,最后重新安装客户端. 或者将客户端从回收站移动到正常的工作组.