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 ...
随机推荐
- EF Core预编译模型Compiled Model
前言 最近还在和 npgsql 与 EF Core 斗争,由于 EF Core 暂时还不支持 AOT,因此在 AOT 应用程序中使用 EF Core 时,会提示问题: 听这个意思,似乎使用 Compi ...
- 【VMware vCenter】使用cmsso-util命令进行链接、删除、修改多个vCenter Server(VCSA)的SSO域。
VMware vCenter Server 支持新安装的时候选择将vCenter SSO域加入到另外一个现有的SSO域中,同时也支持使用cmsso-util命令将现有的两个或多个vCenter SSO ...
- js 通过id、pid遍历集合获得树结构
原数据 let adreeJson = [ {id: 1, name: '陕西省', pid: 0}, {id: 2, name: '山西省', pid: 0}, {id: 3, name: '广东省 ...
- 主数据管理系统(MDM)集成方案
在当今社会,数据已成为企业发展的宝贵财富.然而,大多数企业面临着数据散落在多个系统中.无法互相印证和共享的问题,导致数据使用效率低下.为解决这个问题,目前有两种典型途径:建设公司级系统或建立数据共享平 ...
- 文心一言 VS 讯飞星火 VS chatgpt (156)-- 算法导论12.3 3题
三.用go语言,对于给定的 n 个数的集合,可以通过先构造包含这些数据的一棵二叉搜索树(反复使用TREE-INSERT 逐个插入这些数),然后按中序遍历输出这些数的方法,来对它们排序.这个排序算法的最 ...
- 在 JMeter 中使用 JSON 提取器提取特定条件下的值
当你需要在 JMeter 中对接收到的 JSON 响应进行处理时,JSON 提取器是一个非常有用的工具.在本文中,我们将讨论如何使用 JSON 提取器来提取特定条件下的值,以满足你的需求. 问题描述 ...
- ubuntu安装cudnn
有些忙,这一段时间,博客就随便写写了--- 默认cuda安装好了,这里就不多说了,我们从cuda的环境变量开始说起: 配置cuda环境变量: 打开终端,输入"gedit ~/.bashrc& ...
- The fourth day learning summary
一.for 循环循环就是重复做某件事,for循环是python提供第二种循环机制(第一种是while循环),理论上for循环能做的事情,while循环都可以做.目的:之所以要有for循环,是因为for ...
- Python代码中的偏函数
技术背景 在数学中我们都学过偏导数\(\frac{\partial f(x,y)}{\partial x}\),而这里我们提到的偏函数,指的是\(f(y)(x)\).也就是说,在代码实现的过程中,虽然 ...
- 【UniApp】-uni-app-打包成网页
前言 经过上一篇文章的介绍,已经将这个计算器的计算功能实现了,接下来就是我们项目当中的一个发包上线阶段,我模拟一下,目的就是为了给大家介绍一下,uni-app是如何打包成网页的. 除了可以打包成网页, ...