我们的人生能走多远,看与谁同行;有多大成就,看有谁指点。
参考 LeetCode 30. 串联所有单词的子串。
题目
给定一个字符串 s 和一个字符串数组 words。 words 中所有字符串 长度相同。
s 中的 串联子串 是指一个包含 words 中所有字符串以任意顺序排列连接起来的子串。
例如,如果 words = ["ab","cd","ef"], 那么 "abcdef", "abefcd","cdabef", "cdefab","efabcd", 和 "efcdab" 都是串联子串。 "acdbef" 不是串联子串,因为他不是任何 words 排列的连接。
返回所有串联字串在 s 中的开始索引。你可以以 任意顺序 返回答案。
输入:s = "barfoofoobarthefoobarman", words = ["bar","foo","the"]
输出:[6,9,12]
解释:因为 words.length == 3 并且 words[i].length == 3,所以串联子串的长度必须为 9。
子串 "foobarthe" 开始位置是 6。它是 words 中以 ["foo","bar","the"] 顺序排列的连接。
子串 "barthefoo" 开始位置是 9。它是 words 中以 ["bar","the","foo"] 顺序排列的连接。
子串 "thefoobar" 开始位置是 12。它是 words 中以 ["the","foo","bar"] 顺序排列的连接。
解题思路
- 哈希表:可以考虑存储所有单词的词频,遍历字符串时尝试计算指定长度的词频进行比较是否相同。
哈希表
class Solution {
public List<Integer> findSubstring(String s, String[] words) {
List<Integer> ans = new ArrayList<>();
char[] cs = s.toCharArray();
int n = cs.length,wordLen = words[0].length();
int targetLen = words.length * wordLen;
if(n < targetLen) return ans;
//预处理哈希表判断是否为words中字符串
HashMap<String,Integer> hm = new HashMap<>(); //有重复不能使用set
for(String word : words) hm.put(word,hm.getOrDefault(word,0)+1);
//枚举固定长度
for(int i = 0,j = 0; i + targetLen <= n;i++,j=i) {
HashMap<String,Integer> map = new HashMap<>();
while(j-i+1 <= targetLen) {
String cur = s.substring(j,j+wordLen);
if(!hm.containsKey(cur)) break;
map.put(cur,map.getOrDefault(cur,0)+1);
if(map.get(cur) > hm.get(cur)) break;
j += wordLen;
if(j-i == targetLen) {
ans.add(i);
break;
}
}
}
return ans;
}
}
复杂度分析
- 时间复杂度:
O(nkw),n为字符串s长度,k为单词个数,w为单词长度。 - 空间复杂度:
O(k),使用哈希表记录每个单词的词频。







网友评论