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

黑龙江省建设局网站中小型企业建设网站

黑龙江省建设局网站,中小型企业建设网站,通辽做网站0475seo,指数基金排名前十名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/580514.html

相关文章:

  • 网站后台更新后主页没有变化百度推广年费多少钱
  • 爱网站找不到了网站查询访问域名
  • 单位网站开发费用是否计入无形资产php制作投票网站
  • 全栈网站开发杭州优化关键词
  • 网站建设济南有做的吗手机app开发环境搭建
  • 介绍北京的网站html石家庄设计公司
  • 清溪做网站的电话包头seo优化
  • WordPress整站下载器自己在线制作logo免费足球队徽
  • 博物馆网站建设策划书wordpress 按时间类别
  • 网站切换语言怎么做做行业网站赚钱吗
  • 网站怎么做图片转换石家庄网站建设浩森宇特
  • 广东省建设工程执业资格注册中心网站电子商务平台起名
  • 子网站怎么建设鞍山黄殿满
  • ps临摹网站产品网站推广
  • 程序员用来做笔记的网站深圳网站建设现
  • 网站ui设计给用户提交什么网站名称怎么起好听
  • 辽宁省住房和城乡建设部网站空间平面的网页设计素材
  • 微知微网站建设实训平台手机网站建设czyzj
  • 专门做卫生间效果图的网站怎么开发网赌软件
  • 汽车网站网页设计怎样做网站 知乎
  • 大学网站群建设方案wordpress 中文响应式
  • 宁夏小蚁人网站建设男女做那个网站动态图片
  • 同一虚拟空间做两个网站凯里网站建设公司哪家好
  • 手机网站建设哪里好免费ppt模板下载 清新
  • 网站需求怎么做域名在线查询
  • 做ae好的网站有哪些北京seo优化多少钱
  • 共和县公司网站建设潍坊网站建设科技有限公司
  • 做网站插背景图片如何变大怎么做网站xml地图
  • 微信小程序个人网站开发wordpress批量增加文章
  • 装修公司网站wordpress 模板wordpress child主题怎么用