[LeetCode] 30. Substring with Concatenation of All Words
You are given a string s and an array of strings words of the same length. Return all starting indices of substring(s) in s that is a concatenation of each word in words exactly once, in any order, and without any intervening characters.
You can return the answer in any order.
Example 1:
Input: s = "barfoothefoobarman", words = ["foo","bar"] Output: [0,9] Explanation: Substrings starting at index 0 and 9 are "barfoo" 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: []
Example 3:
Input: s = "barfoofoobarthefoobarman", words = ["bar","foo","the"] Output: [6,9,12]
Constraints:
1 <= s.length <= 104sconsists of lower-case English letters.1 <= words.length <= 50001 <= words[i].length <= 30words[i]consists of lower-case English letters.
串联所有单词的子串。
给定一个字符串 s 和一些 长度相同 的单词 words 。找出 s 中恰好可以由 words 中所有单词串联形成的子串的起始位置。
注意子串要与 words 中的单词完全匹配,中间不能有其他字符 ,但不需要考虑 words 中单词串联的顺序。
来源:力扣(LeetCode)
链接:https://leetcode.cn/problems/substring-with-concatenation-of-all-words
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
思路是滑动窗口(sliding window),但是没法套用之前的模板。注意这个题给的条件,words 里面每个单词是等长的,这个条件会使得这个题目简单些。首先创建一个 hashmap 把 words 里面的所有单词和出现次数都记录下来。接着开始遍历字符串 s,每移动一个字符,就要复制一次之前的 hashmap,因为这里的思路是需要看从起点 i 开始的 substring 是否包含 hashmap 里面存的所有单词(及其次数)。当找到一个子串的时候,需要判断这个子串是否还在 hashmap 里,如果这个子串不存在或者次数已经为 0 了则 break,说明以当前 i 为起点的子串无效;如果这个子串存在于 hashmap 则--,同时 words 的个数 K 也要--,这样当 K == 0 的时候就可以知道所有单词都遍历完了,可以把这个子串的起始位置 i 加入结果集了。
时间O(n^2)
空间O(n)
Java实现一 - 超时
1 class Solution { 2 public List<Integer> findSubstring(String s, String[] words) { 3 List<Integer> res = new ArrayList<>(); 4 // corner case 5 if (s == null || words == null || words.length == 0) { 6 return res; 7 } 8 9 // normal case 10 // 单词个数 11 int n = words.length; 12 // 单词长度 13 int m = words[0].length(); 14 HashMap<String, Integer> map = new HashMap<>(); 15 for (String str : words) { 16 map.put(str, map.getOrDefault(str, 0) + 1); 17 } 18 19 for (int i = 0; i <= s.length() - n * m; i++) { 20 HashMap<String, Integer> copy = new HashMap<>(map); 21 int count = n; 22 int j = i; 23 while (count > 0) { 24 String str = s.substring(j, j + m); 25 if (!copy.containsKey(str) || copy.get(str) < 1) { 26 break; 27 } 28 copy.put(str, copy.get(str) - 1); 29 count--; 30 j += m; 31 } 32 if (count == 0) { 33 res.add(i); 34 } 35 } 36 return res; 37 } 38 }
Java实现二,可以通过。无需像实现一那样一步一步地看 input 字符串。
1 class Solution { 2 public List<Integer> findSubstring(String s, String[] words) { 3 List<Integer> res = new ArrayList<>(); 4 int wordLen = words[0].length(); 5 int wordCount = words.length; 6 int n = s.length(); 7 int m = wordLen * wordCount; 8 9 HashMap<String, Integer> map = new HashMap<>(); 10 for (String word : words) { 11 map.put(word, map.getOrDefault(word, 0) + 1); 12 } 13 14 for (int i = 0; i < wordLen; i++) { 15 int left = i; 16 int right = i; 17 HashMap<String, Integer> wordsFound = new HashMap<>(); 18 int count = 0; 19 20 while (right + wordLen <= s.length()) { 21 String word = s.substring(right, right + wordLen); 22 right += wordLen; 23 if (map.containsKey(word)) { 24 wordsFound.put(word, wordsFound.getOrDefault(word, 0) + 1); 25 count++; 26 27 // 如果当前单词数量超过预期数量,则移动左指针 28 while (wordsFound.get(word) > map.get(word)) { 29 String leftWord = s.substring(left, left + wordLen); 30 wordsFound.put(leftWord, wordsFound.get(leftWord) - 1); 31 count--; 32 left += wordLen; 33 } 34 if (count == wordCount) { 35 res.add(left); 36 } 37 } else { 38 wordsFound.clear(); 39 count = 0; 40 left = right; 41 } 42 } 43 } 44 return res; 45 } 46 }
JavaScript实现
1 /** 2 * @param {string} s 3 * @param {string[]} words 4 * @return {number[]} 5 */ 6 var findSubstring = function (s, words) { 7 // corner case 8 if (s == null || words == null || words.length == 0) { 9 return []; 10 } 11 12 // normal case 13 let res = []; 14 let n = words.length; 15 let m = words[0].length; 16 let map = {}; 17 for (let str of words) { 18 map[str] = (map[str] || 0) + 1; 19 } 20 21 for (let i = 0; i <= s.length - n * m; i++) { 22 let copy = { ...map }; 23 let k = n; 24 let j = i; 25 while (k > 0) { 26 let str = s.substring(j, j + m); 27 if (!copy[str] || copy[str] < 1) { 28 break; 29 } 30 copy[str]--; 31 k--; 32 j += m; 33 } 34 if (k == 0) { 35 res.push(i); 36 } 37 } 38 return res; 39 };

浙公网安备 33010602011771号