您的位置:首页 > 其它

Leetcode 30. Substring with Concatenation of All Words

2016-05-15 10:00 411 查看


30. Substring with Concatenation of All Words

Total Accepted: 54574 Total
Submissions: 261476 Difficulty: Hard

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 wordsexactly once and without any intervening characters.
For example, given:

s:
"barfoothefoobarman"


words:
["foo", "bar"]

You should return the indices:
[0,9]
.

(order does not matter).

解法一:参考这里

先统计words中的单词和频率。然后从每个位置开始,判断长度为words.length*words[0].length()的字符串满足要求否,因为不满足会直接break,所以判断长度最多为那么长。每次判断新建一个Map复制之前的数据,这样保证单词出现一次并且只有一次。

public class Solution { // 190ms
public List<Integer> findSubstring(String s, String[] words) {
List<Integer> res = new ArrayList<Integer>();
if(s == null || s.length()==0) return res;
Map<String, Integer> hm = new HashMap<String, Integer>();
int n = words.length, m = words[0].length(), l = s.length();
for(int i=0; i<n; i++){
if(hm.containsKey(words[i])){
hm.put(words[i], hm.get(words[i])+1);
}else{
hm.put(words[i], 1);
}
}

for(int i=0; l-i>=m*n; i++){
Map<String, Integer> temp = new HashMap<String, Integer>(hm);
for(int j=0; j<n; j++){
String substr = s.substring(i+j*m, i+(j+1)*m);
if(temp.containsKey(substr)){
if(temp.get(substr)==1) temp.remove(substr);
else temp.put(substr, temp.get(substr)-1);
}else{
break;
}
}
if (temp.size()==0) res.add(i);
}

// int i = 0;   // 不同写法,和上面运行时间一样,但是上面的for loop 经常报超时(80%概率)。
// while(l-i>=m*n){
//     Map<String, Integer> temp = new HashMap<String, Integer>(hm);
//     for(int j=0; j<n; j++){
//         String substr = s.substring(i+j*m, i+(j+1)*m);
//         if(temp.containsKey(substr)){
//             if(temp.get(substr)==1) temp.remove(substr);
//             else temp.put(substr, temp.get(substr)-1);
//         }else{
//             break;
//         }
//     }
//     if (temp.size()==0) res.add(i); i++;
// }
return res;
}
}


解法二:解释大概和这里相同,code来自这里

思路是start的位置有单词长度个。然后end指针从start开始,如果从end开始的单词长度的字符串不在词典里,那么start指针右移单词个长度;否则当前的map中该单词频率+1,并判断子窗口的长度是否满足要求,满足则start加入结果中。有一种情况是碰到重复的,则需要跳过从start开始的子串,直到使当前发生dup的单词频率减少,此过程中start不断变化,相当于更新起点。

public class Solution{ // 20ms
public ArrayList<Integer> findSubstring(String S, String[] L) {
final Map<String, Integer> need = new HashMap<String, Integer>();
for (int i = 0; i < L.length; i++) {
need.put(L[i], need.get(L[i]) == null ? 1 : need.get(L[i]) + 1);
}
ArrayList<Integer> result = new ArrayList<Integer>();
for (int i = 0; i < L[0].length(); i++) { // 只有单词长度个开始位置,防止重复。
populateResult(result, S, L, i, need);
}
return result;
}
private void populateResult(ArrayList<Integer> result, String S, String[] L, int start, final Map<String, Integer> need) {
int k = L[0].length();
HashMap<String, Integer> has = new HashMap<String, Integer>();
for (int end = start; end <= S.length() - k; end += k) {
String sub = S.substring(end, end + k);
if (need.containsKey(sub)) {
while (has.get(sub) == need.get(sub)) { // 遇到与sub重复的,则跳过开始已匹配的子串,直到去除重复的sub
String tmp = S.substring(start, start + k);
has.put(tmp, has.get(tmp) - 1);
start += k;
}
has.put(sub, has.get(sub) == null ? 1 : has.get(sub) + 1);
if (end - start + k == L.length * L[0].length())
result.add(start);
} else {
has.clear();
start = end + k;
}
}
}
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: