【LeetCode】30.串联所有单词的子串

30.串联所有单词的子串

知识点:字符串;滑动窗口;哈希表

题目描述

给定一个字符串 s 和一些 长度相同 的单词 words 。找出 s 中恰好可以由 words 中所有单词串联形成的子串的起始位置。

注意子串要与 words 中的单词完全匹配,中间不能有其他字符 ,但不需要考虑 words 中单词串联的顺序。

示例
示例 1: 输入:s = "barfoothefoobarman", words = ["foo","bar"] 输出:[0,9] 解释: 从索引 0 和 9 开始的子串分别是 "barfoo""foobar"输出的顺序不重要, [9,0] 也是有效答案。 示例 2: 输入:s = "wordgoodgoodgoodbestword", words = ["word","good","best","word"] 输出:[] 示例 3: 输入:s = "barfoofoobarthefoobarman", words = ["bar","foo","the"] 输出:[6,9,12]

解法一:滑动窗口

这其实也是滑动窗口的一道典型题目
找到包含words中单词的子串;要注意到题目中一个条件,words中的单词都是长度相同的,子串其实就可以去想想滑动窗口。
当然也可以直接看word中的长度,然后每次截取这么长的子串,然后统计子串中的单词和个数,形成第二个哈希表,看和word中的哈希表是否相同。这样的话两次for。
当然,我们可以用滑动窗口来优化这道题。
初始:统计words中每个字符的数量,形成hashmap1;
窗口的移动都是以单词的长度为单位进行的, 没必要一个字符一个字符的去移动;
1.right右移,试图去找满足条件的窗口

if当前的单词不在hashmap1中,那前面肯定都不对了,left直接移动到right即可; if当前的单词在hashmap1中,并且还没有超过hashmap1中的个数,那right可以继续移动 if当前的单词在hashmap1中,但是当前窗口中包含的目前这个单词个数已经超过了hashmap1中的个数,那就要把当前这个单词对应的前面的部分都移出去,也就是左窗口要移动 所以怎么能够知道当前窗口内对应的单词和个数呢,维持一个当前窗口的hashmap2,

2.left右移:

当现在的窗口内当前的单词数量超过了需要的个数,那left要把这个单词和其之前的单词都移动出去(因为if left只移动一个,假设目前的这个单词在后面重复,根本没有意义,因为还是多着呢)。 除此之外,维持一个所需要的单词总数量,这样可以知道什么时候满足要求,向res中添加答案
  • 其实仔细想一下这个过程,仍然是满足滑动窗口的思想:毛毛虫模型
    右窗口移动,寻找可行解,然后会破坏掉条件(对应本题就是出现了没有的单词或者单词出现的过多了)
    然后右边不动了,左窗口移动,让整个窗口仍然满足条件
    与之前的难点就在于在其中穿插了两个哈希表,然后在其中判断窗口是否会满足最后答案的要求。
from collections import Counter, defaultdict class Solution: def findSubstring(self, s: str, words: List[str]) -> List[int]: res = [] allwords_count = Counter(words) # 所有单词的数量的哈希表 word_count = len(words) # 单词的数量 oneword_len = len(words[0]) #每个单词的长度 for i in range(oneword_len): #前面不清楚具体是由哪个字符开始的 left = right = i count = 0 #已经满足的单词数量 windowwords_count = defaultdict(int) # 统计窗口内每个单词数量的哈希表 while right + oneword_len <= len(s): cur_word = s[right:right+oneword_len] #当前单词 right += oneword_len if cur_word not in allwords_count: #肯定匹配失败 left = right #窗口右移 windowwords_count.clear() #字典清空 count = 0 else: #有这个单词 windowwords_count[cur_word] += 1 count += 1 while windowwords_count.get(cur_word) > allwords_count.get(cur_word): popword = s[left: left+oneword_len] #移出的单词 windowwords_count[popword] -= 1 count -= 1 left += oneword_len #次数都减1,左窗口右移 if count == word_count: res.append(left) return res

__EOF__

本文作者Curryxin
本文链接https://www.cnblogs.com/Curryxin/p/16130305.html
关于博主:评论和私信会在第一时间回复。或者直接私信我。
版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!
声援博主:如果您觉得文章对您有帮助,可以点击文章右下角推荐一下。您的鼓励是博主的最大动力!
posted @   Curryxin  阅读(82)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 全程不用写代码,我用AI程序员写了一个飞机大战
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· 记一次.NET内存居高不下排查解决与启示
· DeepSeek 开源周回顾「GitHub 热点速览」
· 白话解读 Dapr 1.15:你的「微服务管家」又秀新绝活了
Live2D
欢迎阅读『【LeetCode】30.串联所有单词的子串』
点击右上角即可分享
微信分享提示