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.
For example, given:
s: "barfoothefoobarman"
words: ["foo", "bar"]
You should return the indices: [0,9]
.
(order does not matter).
解题思路:
这道题看下来难点在于时间复杂度的问题,思路的话还好,就是用一个for循环,对s里面的每一个值,查找说以这个值为起始,以words.length*words[0].length()为长度的substring能不能满足要求。不断遍历就可以了。
我的第一个想法就是在每次匹配中,用一个数组来记录说words里面每个值是否已经用于匹配了,如果已经匹配了就标1,未匹配就标0。用这样来进行判断。结果就是TLE了,很明显,因为对于每一个sub块,都需要进行一个长度为words.length的for循环。
public class Solution {
public List<Integer> findSubstring(String s, String[] words)
{
List<Integer> answer = new ArrayList<Integer>();
if(words.length == 0 || words[0] == null ||words[0].length() == 0 )
return answer;
int len1 = words[0].length();
int len2 = words.length;
int size = len1*len2;
for(int i = 0;i<=s.length()-size;i++)
{
int index1 = 0;
int index2 = i;
int[] count = new int[len2];
while(index1 < len2)
{
String sub = s.substring(index2, index2+len1);
int j;
for(j = 0;j<len2;j++)
{
if(count[j] != 0)
continue;
if(words[j].equals(sub))
{
count[j] = 1;
break;
}
}
if(j == len2)
break;
index2 += len1;
index1 ++;
}
if(index1 == len2)
answer.add(i);
}
return answer;
}
}
第二个想法就是用HashMap了。起始一开始想过用HashMap的,但是感觉空间复杂度比较大,不过它的好处就是每隔sub块只需要进行一个查找。结果在跑的时候,有时候TLE有时候AC了。。。
public class Solution {
public List<Integer> findSubstring(String s, String[] words)
{
List<Integer> answer = new ArrayList<Integer>();
if(words.length == 0 || words[0] == null ||words[0].length() == 0 )
return answer;
int len1 = words[0].length();
int len2 = words.length;
int size = len1*len2;
Map<String,Integer> map = new HashMap<String,Integer>();
for(int i = 0;i<len2;i++)
{
if(map.containsKey(words[i]))
map.put(words[i], map.get(words[i])+1);
else
map.put(words[i], 1);
}
for(int i = 0;i<=s.length()-size;i++)
{
Map<String,Integer> map2 = new HashMap<String,Integer>(map);
int index1 = 0;
int index2 = i;
while(index1 < len2)
{
String sub = s.substring(index2, index2+len1);
if(map2.containsKey(sub))
{
int count = map2.get(sub);
if(count == 1)
map2.remove(sub);
else
map2.put(sub, count-1);
index1++;
index2 += len1;
}
else
break;
}
if(index1 == len2)
answer.add(i);
}
return answer;
}
}
最后是leetcode上的一个代码,效果很好!!!由于我要回宿舍了看人民的名义了所以先把代码贴着,等明天有空来看。
public class Solution {
public List<Integer> findSubstring(String s, String[] words) {
int N = s.length();
List<Integer> indexes = new ArrayList<Integer>(s.length());
if (words.length == 0) {
return indexes;
}
int M = words[0].length();
if (N < M * words.length) {
return indexes;
}
int last = N - M + 1;
//map each string in words array to some index and compute target counters
Map<String, Integer> mapping = new HashMap<String, Integer>(words.length);
int [][] table = new int[2][words.length];
int failures = 0, index = 0;
for (int i = 0; i < words.length; ++i) {
Integer mapped = mapping.get(words[i]);
if (mapped == null) {
++failures;
mapping.put(words[i], index);
mapped = index++;
}
++table[0][mapped];
}
//find all occurrences at string S and map them to their current integer, -1 means no such string is in words array
int [] smapping = new int[last];
for (int i = 0; i < last; ++i) {
String section = s.substring(i, i + M);
Integer mapped = mapping.get(section);
if (mapped == null) {
smapping[i] = -1;
} else {
smapping[i] = mapped;
}
}
//fix the number of linear scans
for (int i = 0; i < M; ++i) {
//reset scan variables
int currentFailures = failures; //number of current mismatches
int left = i, right = i;
Arrays.fill(table[1], 0);
//here, simple solve the minimum-window-substring problem
while (right < last) {
while (currentFailures > 0 && right < last) {
int target = smapping[right];
if (target != -1 && ++table[1][target] == table[0][target]) {
--currentFailures;
}
right += M;
}
while (currentFailures == 0 && left < right) {
int target = smapping[left];
if (target != -1 && --table[1][target] == table[0][target] - 1) {
int length = right - left;
//instead of checking every window, we know exactly the length we want
if ((length / M) == words.length) {
indexes.add(left);
}
++currentFailures;
}
left += M;
}
}
}
return indexes;
}
}