30.substring-with-concatenation-of-all-words-cn

题目地址

https://leetcode.com/problems/substring-with-concatenation-of-all-words/

题目描述

You are given a string, s, and a list of words, words, that are all of the same length. Find all starting indices of substring(s)
in s that is a concatenation of each word in words exactly once and without any intervening characters.

Example 1:
Input:
  s = "barfoothefoobarman",
  words = ["foo","bar"]
Output: [0,9]
Explanation: Substrings starting at index 0 and 9 are "barfoor" and "foobar" respectively.
The output order does not matter, returning [9,0] is fine too.

Example 2:
Input:
  s = "wordgoodgoodgoodbestword",
  words = ["word","good","best","word"]
Output: []

思路

题意: 给定一个字符串(String s), 给定n个单词组成的字符串数组(String[] words), 找出所有子串(substring)的起始下标(start index), 使得该子串包含所有的单词, 每个单词的个数也要相同(子串中单词顺序任意).

解法一 - 暴力

先简单,直接,暴力的解 (暴力出奇迹, 😄).

遍历字符s,判断每个子串是匹配字符串数组中所有单词, 如果匹配, 记录下标 (index), 条件中每个单词的长度是相同的, 所以从当前下标, 可以很快得到单词长度的子串并进行比较.

由于不考虑顺序,这里可以用Hashmap先保存所有单词,并记录单词出现的次数. Map<Key, Value>- key 是单词, value 是单词的个数.

遍历字符s的时候,扫描并记录子串的单词和单词个数,用另一个HashMap保存, (key 是当前子串的单词, value 是当前子串单词出现的个数), 并与单词数组中单词和单词出现个数比较,

  1. 如果当前单词不在单词数组中,那么以当前字符开头的子串不可能满足情况, 提前结束, 往后移动到下一个字符的子串.

  2. 如果当前单词个数超过单词数组, 也不可能满足, 结束, 往后移动到下一个

  3. 满足的单词的数量(count)加1.

  4. 比较满足的单词数量(count == wordNum), 满足, 记录下当前下标(index), 移动到下一个字符

  5. 每次移动第二个HashMap清空, 重新计算

例子:

复杂度分析

时间复杂度(TC): O(n * m) - n是s的长度, m是单词(words)的个数.

空间复杂度(SC): O(m)

解法二

参考 [shichaotan的解法](https://leetcode.com/problems/substring-with-concatenation-of-all-words/discuss/13656/An-O(N)-solution-with-detailed-explanation)

在解法一中,我们每次移动一个字符(char), 这样就造成了很多不必要的重复计算. 在解法二中,每次移动一个单词(word), 这样可以以word长度分类移动, 例如: word长度为3, 那么就可以分为3类来移动.

例子如下图, 对于单词(word)长度为3, 分为 i = 0, i = 1, i = 2 三类移动单词的距离.

substring concatenation 3
substring concatenation 4
substring concatenation 5

从例子中,我们可以发现,按单词(word)移动,在解法一中,考虑了三种情况,那么解法二可以针对这三点进行优化:

  1. 当面单词不满足(不在给定单词数组(words)中).

  2. 当面单词出现在单词数组(words)中,但个数超过给定的个数

  3. 往后移动的过程,不需要每次都清空HashMap, 造成重复计算, 浪费资源.

对于1中单词不满足了, 可以略过(skip)掉不满足的这个单词前面所有的移动, 直接移动到下一个单词. 例如: alt text

对于2中单词满足, 但是个数超过给定个数的情况, alt text

这样就不需要每次移动都清空 HashMap, 而是当单词不满足的情况下, 清空HashMap 即可.

相较于解法一中, 每次移动一个字符都需要清空HashMap,节省很多时间的计算

复杂度分析

时间复杂度(TC): O(n) - n 为 S 的长度

空间复杂度(SC): O(m) - m 为单词个数

代码 (Java/Python3)

解法一 - 暴力

解法二

Python code from @sunboman

相似题目

Minimum Window Substring

Last updated

Was this helpful?