当前位置: 首页 > news >正文

荆州建设局网站邯郸信息港征婚

荆州建设局网站,邯郸信息港征婚,南宁制作网站多少钱,平面设计公司招聘要求Leetcode 30. 串联所有单词的子串 是一道经典的字符串滑动窗口问题。这题考察字符串切分、哈希表匹配以及滑动窗口的灵活应用。解题难度较高,需要对循环和判断逻辑有良好的掌握。 题目描述 给定一个字符串 s 和一组长度都相同的单词数组 words,找出 s 中…

Leetcode 30. 串联所有单词的子串 是一道经典的字符串滑动窗口问题。这题考察字符串切分、哈希表匹配以及滑动窗口的灵活应用。解题难度较高,需要对循环和判断逻辑有良好的掌握。


题目描述

给定一个字符串 s 和一组长度都相同的单词数组 words,找出 s 中恰好可以由数组中所有单词连接在一起的连续子字符串的起始索引。这些单词在子字符串中可以以任意顺序排列,但每个单词必须完全匹配。


示例

输入: s = "barfoothefoobarman", words = ["foo","bar"]
输出: [0,9]
解释: 子串是 "barfoo" 和 "foobar",它们的起始索引分别为 0 和 9。输入: s = "wordgoodgoodgoodbestword", words = ["word","good","best","word"]
输出: []输入: s = "barfoofoobarthefoobarman", words = ["bar","foo","the"]
输出: [6,9,12]

解法 1:滑动窗口法

思路

将问题转化为固定宽度为 totalLen = words.length * wordLen 的滑动窗口问题:

  1. 窗口大小:
    • 由于单词长度都一样,窗口的大小固定为 totalLen
    • 可以遍历 s 的每个可能起点,从中截取长度为 totalLen 的窗口。
  2. 匹配机制:
    • 用一个 HashMap 记录 words 中每个单词的频次 (wordFreq)。
    • 每个窗口逐个截取长度为 wordLen 的单词片段,统计其出现频次 (currentFreq)。
    • 如果当前窗口内所有单词的出现频次完全匹配 wordFreq,则当前窗口为有效窗口。
  3. 滑动优化:
    • 滑动窗口通常从左到右依次移动,通过减少重新计算提升效率。

代码模板

import java.util.*;class Solution {public List<Integer> findSubstring(String s, String[] words) {List<Integer> result = new ArrayList<>();if (s == null || s.length() == 0 || words == null || words.length == 0) {return result;}int wordLen = words[0].length(); // 单词长度int totalLen = wordLen * words.length; // 总窗口长度// 单词频次统计Map<String, Integer> wordFreq = new HashMap<>();for (String word : words) {wordFreq.put(word, wordFreq.getOrDefault(word, 0) + 1);}// 滑动窗口for (int i = 0; i < wordLen; i++) { // 启动多个滑动窗口int left = i, right = i, count = 0;Map<String, Integer> currentFreq = new HashMap<>();while (right + wordLen <= s.length()) {String word = s.substring(right, right + wordLen);right += wordLen;// 处理当前单词if (wordFreq.containsKey(word)) {currentFreq.put(word, currentFreq.getOrDefault(word, 0) + 1);count++;// 如果某单词超出频次限制,缩小窗口while (currentFreq.get(word) > wordFreq.get(word)) {String leftWord = s.substring(left, left + wordLen);currentFreq.put(leftWord, currentFreq.get(leftWord) - 1);left += wordLen;count--;}// 检查是否完全匹配if (count == words.length) {result.add(left);}} else {// 非法单词,重置窗口状态currentFreq.clear();count = 0;left = right;}}}return result;}
}

复杂度分析

  • 时间复杂度:
    • 单词数为 n,单词长度为 wordLen,字符串长度为 m
    • 滑动窗口遍历最多 m / wordLen 次,每次窗口内的频率判断需要 O(n)。
    • 总时间复杂度为 O(m * n / wordLen)
  • 空间复杂度: O(n)
    • 需要存储 wordFreqcurrentFreq 两个 HashMap。

适用场景

  • 适用于输入字符串较大,但单词数量较少的情况。
  • 高效处理,能够正确识别多种模式。

解法 2:分块扫描

思路

  • 类似滑动窗口,但优化起点扫描的策略。由于单词长度固定,字符串可以按照 wordLen 等分。
  • 对每个可能的起点进行独立的分块滑动扫描,减少重复逻辑。

代码模板

class Solution {public List<Integer> findSubstring(String s, String[] words) {List<Integer> result = new ArrayList<>();if (s == null || s.length() == 0 || words == null || words.length == 0) {return result;}int wordLen = words[0].length();int totalLen = wordLen * words.length;if (s.length() < totalLen) {return result;}Map<String, Integer> wordFreq = new HashMap<>();for (String word : words) {wordFreq.put(word, wordFreq.getOrDefault(word, 0) + 1);}for (int i = 0; i < wordLen; i++) {Map<String, Integer> currentFreq = new HashMap<>();int left = i, count = 0;for (int right = i; right + wordLen <= s.length(); right += wordLen) {String word = s.substring(right, right + wordLen);if (wordFreq.containsKey(word)) {currentFreq.put(word, currentFreq.getOrDefault(word, 0) + 1);count++;while (currentFreq.get(word) > wordFreq.get(word)) {String removedWord = s.substring(left, left + wordLen);currentFreq.put(removedWord, currentFreq.get(removedWord) - 1);count--;left += wordLen;}if (count == words.length) {result.add(left);}} else {currentFreq.clear();count = 0;left = right + wordLen;}}}return result;}
}

复杂度分析

  • 时间复杂度: O(m * n / wordLen)。
  • 空间复杂度: O(n) (存储单词字典)。

解法 3:暴力法

思路

  1. 枚举字符串的所有子串,判断是否等于 words 的任意排列。
  2. 将字符串切分为固定大小的单词并比较频次。

代码模板

class Solution {public List<Integer> findSubstring(String s, String[] words) {List<Integer> result = new ArrayList<>();if (s == null || s.length() == 0 || words == null || words.length == 0) {return result;}int wordLen = words[0].length();int totalLen = wordLen * words.length;Map<String, Integer> wordFreq = new HashMap<>();for (String word : words) {wordFreq.put(word, wordFreq.getOrDefault(word, 0) + 1);}for (int i = 0; i <= s.length() - totalLen; i++) {String sub = s.substring(i, i + totalLen);Map<String, Integer> currentFreq = new HashMap<>();boolean isValid = true;for (int j = 0; j < sub.length(); j += wordLen) {String word = sub.substring(j, j + wordLen);currentFreq.put(word, currentFreq.getOrDefault(word, 0) + 1);if (!wordFreq.containsKey(word) || currentFreq.get(word) > wordFreq.get(word)) {isValid = false;break;}}if (isValid) {result.add(i);}}return result;}
}

复杂度分析

  • 时间复杂度: O(m * n)
    • 对于每个起点,我们需要遍历每个单词,再比较频次。
  • 空间复杂度: O(n)

快速 AC 策略

  1. 首选滑动窗口法 (解法 1):
    • 时间效率高,代码清晰,非常适合面试中快速实现。
  2. 可以考虑分块扫描 (解法 2):
    • 针对特定输入大小,可以优化性能。
  3. 避免使用暴力法 (解法 3):
    • 尽管清晰直观,但性能差,不适合大规模输入。

在面试或实际开发中,熟练掌握滑动窗口模板,能够快速解决这类问题!

http://www.dtcms.com/a/582990.html

相关文章:

  • 有口碑的番禺网站建设深圳招聘网最新招聘信息
  • 网站前台如何刷新整合营销案例
  • 可以自己做网站卖东西搜索引擎优化规则
  • C++ this指针、常函数、内联函数
  • 网页设计制作网站大一素材网站集群怎么做
  • Hudson River Trading VO 面经分享|一场关于极限思维与逻辑速度的考验
  • html5企业网站案例企业免费自助建站系统
  • 企业建设网站价格成都专业网站搭建公司
  • 西宁建设网站软件百度导航最新版本免费下载
  • 网站开发后端菜鸟教程网站呢建设
  • JavaScript 使用技巧
  • 提高网站互动性台州住房和城乡建设部网站
  • Spark-3.5.7文档2 - RDD 编程指南
  • 网站公司做网站修改会收费吗电子商务类型的网站
  • flowable使用01
  • 做国外直播网站有哪些渭南seo快速排名
  • 做的网站百度找不到广州市天河区工程建设监督网站
  • 网站攻击方式wordpress手机上用的
  • 攻防世界-Misc-掀桌子
  • 如何用SETNX实现分布式锁
  • 广州市品牌网站建设平台WordPress文章首页缩进
  • 泰兴网站推广wordpress vaptcha
  • AI与就业:在变革中主动驾驭未来
  • container_of宏
  • 创建网站要钱吗windows系统没有wordpress
  • 网站开发流程三大部分测评网站怎么做
  • iPhone 17 Pro Max 的评测和用户反馈
  • Python 中的异步编程:从基础到实战
  • 怎么制作自己的个人网站网址导航发布页
  • 网站建设售后服务方案百度招聘