力扣经典150题第三十二题:串联所有单词的子串

简介: 力扣经典150题第三十二题:串联所有单词的子串

解题思路与实现 - 串联所有单词的子串

问题描述

给定一个字符串 s 和一个字符串数组 words,数组中所有字符串长度相同。s 中的串联子串是指一个包含 words 中所有字符串以任意顺序排列连接起来的子串。找出所有串联子串在 s 中的起始索引。

示例
  1. 输入:s = “barfoothefoobarman”, words = [“foo”,“bar”]
    输出:[0,9]
    解释:子串 “barfoo” 和 “foobar” 都是以 ["foo","bar"] 顺序排列的连接。
  2. 输入:s = “wordgoodgoodgoodbestword”, words = [“word”,“good”,“best”,“word”]
    输出:[]
    解释:无符合条件的串联子串。
  3. 输入:s = “barfoofoobarthefoobarman”, words = [“bar”,“foo”,“the”]
    输出:[6,9,12]
    解释:子串 “foobarthe”、“barthefoo” 和 “thefoobar” 都是以 ["bar","foo","the"] 顺序排列的连接。
解题思路

使用滑动窗口(双指针)和哈希表的方法解决该问题:

  1. 将 words 中的所有单词存入哈希表 wordCount,记录每个单词的出现次数。
  2. 遍历字符串 s,以每个可能的起始位置作为窗口的起点,通过滑动窗口判断是否能匹配所有单词。
  3. 窗口的大小应为 words 中所有单词的总长度。
  4. 滑动窗口每次向右移动一个单词长度,维护一个窗口中包含的单词计数 currentWords。
  5. 若窗口中的单词与 words 中的单词匹配,则将起点加入结果列表。
算法实现
public List<Integer> findSubstring(String s, String[] words) {
    List<Integer> result = new ArrayList<>();
    if (s == null || s.isEmpty() || words == null || words.length == 0) {
        return result;
    }
    
    Map<String, Integer> wordCount = new HashMap<>();
    int wordLength = words[0].length();
    int totalLength = wordLength * words.length;
    
    for (String word : words) {
        wordCount.put(word, wordCount.getOrDefault(word, 0) + 1);
    }
    
    for (int i = 0; i <= s.length() - totalLength; i++) {
        Map<String, Integer> currentWords = new HashMap<>();
        int j = 0;
        
        while (j < words.length) {
            String currentWord = s.substring(i + j * wordLength, i + (j + 1) * wordLength);
            if (!wordCount.containsKey(currentWord)) {
                break;
            }
            currentWords.put(currentWord, currentWords.getOrDefault(currentWord, 0) + 1);
            if (currentWords.get(currentWord) > wordCount.getOrDefault(currentWord, 0)) {
                break;
            }
            j++;
        }
        
        if (j == words.length) {
            result.add(i);
        }
    }
    
    return result;
}
复杂度分析
  • 时间复杂度:O(n * m),其中 n 是字符串 s 的长度,m 是单词数组 words 的长度。
  • 空间复杂度:O(m),哈希表 wordCount 和 currentWords 的空间复杂度为单词数组 words 的长度。
测试与验证

设计不同测试用例,包括空字符串、单个单词、多个单词等情况,验证算法的正确性和效率。

总结

通过本文的详细解题思路和算法实现,可以有效地解决给定字符串中找出所有串联子串的起始索引的问题。利用滑动窗口和哈希表的方法,可以高效地实现该算法。

感谢阅读!

相关文章
|
3天前
|
存储 算法 测试技术
力扣经典150题第三十三题:最小覆盖子串
力扣经典150题第三十三题:最小覆盖子串
6 1
|
18天前
|
算法
【LeetCode刷题】滑动窗口解决问题:串联所有单词的子串(困难)、最小覆盖子串(困难)
【LeetCode刷题】滑动窗口解决问题:串联所有单词的子串(困难)、最小覆盖子串(困难)
|
3天前
|
算法
力扣经典150题第二十一题:反转字符串中的单词
力扣经典150题第二十一题:反转字符串中的单词
6 0
|
3天前
|
算法
力扣经典150题第十九题:最后一个单词的长度
力扣经典150题第十九题:最后一个单词的长度
6 0
|
18天前
|
算法
【经典LeetCode算法题目专栏分类】【第8期】滑动窗口:最小覆盖子串、字符串排列、找所有字母异位词、 最长无重复子串
【经典LeetCode算法题目专栏分类】【第8期】滑动窗口:最小覆盖子串、字符串排列、找所有字母异位词、 最长无重复子串
|
18天前
|
算法
【经典LeetCode算法题目专栏分类】【第3期】回溯问题系列:单词搜索、N皇后问题、判断有效数独、解数独
【经典LeetCode算法题目专栏分类】【第3期】回溯问题系列:单词搜索、N皇后问题、判断有效数独、解数独
|
17天前
|
算法 C++
【数据结构与算法】:关于时间复杂度与空间复杂度的计算(C/C++篇)——含Leetcode刷题-2
【数据结构与算法】:关于时间复杂度与空间复杂度的计算(C/C++篇)——含Leetcode刷题
|
17天前
|
算法 C++
【数据结构与算法】:关于时间复杂度与空间复杂度的计算(C/C++篇)——含Leetcode刷题-1
【数据结构与算法】:关于时间复杂度与空间复杂度的计算(C/C++篇)——含Leetcode刷题
|
18天前
|
索引
【LeetCode刷题】二分查找:山脉数组的峰顶索引、寻找峰值
【LeetCode刷题】二分查找:山脉数组的峰顶索引、寻找峰值
|
18天前
|
算法 容器
【LeetCode刷题】滑动窗口解决问题:水果成篮、找到字符串中所有字母异位词
【LeetCode刷题】滑动窗口解决问题:水果成篮、找到字符串中所有字母异位词