力扣经典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 的长度。
测试与验证

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

总结

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

感谢阅读!

相关文章
|
2月前
Leetcode(最后一个单词长度)
这篇文章介绍了两种解决LeetCode第58题的方法,即计算给定字符串中最后一个单词的长度,方法包括翻转字符串和逆向遍历统计。
20 0
|
2月前
【LeetCode 20】151.反转字符串里的单词
【LeetCode 20】151.反转字符串里的单词
19 0
|
4月前
|
算法
LeetCode第58题最后一个单词的长度
LeetCode第58题"最后一个单词的长度"的解题方法,通过从字符串末尾向前遍历并计数非空格字符,直接得出最后一个单词的长度。
LeetCode第58题最后一个单词的长度
|
4月前
|
算法 JavaScript Python
【Leetcode刷题Python】79. 单词搜索和剑指 Offer 12. 矩阵中的路径
Leetcode第79题"单词搜索"的Python解决方案,使用回溯算法在给定的二维字符网格中搜索单词,判断单词是否存在于网格中。
45 4
|
4月前
|
Python
【Leetcode刷题Python】生词本单词整理
文章提供了一个Python程序,用于帮助用户整理和排版生词本上的单词,包括去除重复单词、按字典序排序,并按照特定的格式要求进行打印排版。
42 3
|
4月前
|
Python
【Leetcode刷题Python】318. 最大单词长度乘积
本文提供了LeetCode题目318的Python编程解决方案,题目要求在一个字符串数组中找出两个不含有公共字母的单词,且这两个单词的长度乘积最大,如果不存在这样的两个单词,则返回0。
21 0
|
6月前
|
存储 算法 测试技术
力扣经典150题第三十三题:最小覆盖子串
力扣经典150题第三十三题:最小覆盖子串
39 1
|
6月前
|
算法
力扣经典150题第二十一题:反转字符串中的单词
力扣经典150题第二十一题:反转字符串中的单词
60 0
|
3月前
|
Unix Shell Linux
LeetCode刷题 Shell编程四则 | 194. 转置文件 192. 统计词频 193. 有效电话号码 195. 第十行
本文提供了几个Linux shell脚本编程问题的解决方案,包括转置文件内容、统计词频、验证有效电话号码和提取文件的第十行,每个问题都给出了至少一种实现方法。
LeetCode刷题 Shell编程四则 | 194. 转置文件 192. 统计词频 193. 有效电话号码 195. 第十行
|
4月前
|
搜索推荐 索引 Python
【Leetcode刷题Python】牛客. 数组中未出现的最小正整数
本文介绍了牛客网题目"数组中未出现的最小正整数"的解法,提供了一种满足O(n)时间复杂度和O(1)空间复杂度要求的原地排序算法,并给出了Python实现代码。
119 2