题目:
给出一个字符串S,和一个字符串数组words,words中包括很多个字符串,每个字符串的长度都相同,并且可能相同的字符串出现多次,现在要求由words中所有的字符串连接之后形成的字符串在S出现的位置。
举例:
S: "barfoothefoobarman"
words: ["foo", "bar"]
返回的结果应该是[0,9],因为barfoo和foobar在S中出现处的头部索引是0和9
思路:
在S中寻找的字符串Str由words中所有的字符串组成,那么字符串Str的长度则由words决定,并且Str按照words中的字符串的长度分割之后,和words中的字符串是一一对应的。例如例子中的barfoo的长度为6,并且将barfoo按照三个三个字母分割后得到bar和foo,在words中的字符串一一对应。
那么从上面的想法中可以得到这样一个方法:
首先,统计words中出现的字符串,和每个字符串出现的个数。
然后,在S中找到一个长度为words字符串个数N*字符串长度L的子串Str,将Str分割成N个长度为L的小串,统计这些串的种类和个数,或者判断这些串是否在words中出现,出现的次数是否相同,如果不同,则继续往下判断下一个长度为N*L的S的子串。
代码:
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
public class Substring_with_Concatenation_of_All_Words {
public static List<Integer> findSubstring(String s, String[] words)
{
List<Integer> result = new ArrayList<>();
int words_size = words.length,s_length = s.length();
if(words_size <= 0 || s_length <= 0) return result;
int length_each_word = words[0].length();
HashMap<String,Integer> map = new HashMap<>();
HashMap<String,Integer> map2 = map;
for(String s1 : words)map.put(s1, map.containsKey(s1)?map.get(s1)+1:1);
for(int i = 0;i < s_length - words_size * length_each_word + 1;i++)
{
map2 = (HashMap<String, Integer>) map.clone();
String str = s.substring(i, i + words_size * length_each_word);
int j,k = 0;
for(j = 0;j < str.length();j = j + length_each_word)
{
String str2 = str.substring(j,j + length_each_word);
if(map2.containsKey(str2))//barfoofoobarthefoobarman
{
int times = map2.get(str2);
if(times > 0) map2.put(str2, --times);
else{k = 1; break;}
}
else{k = 1; break;}
}
if(k == 0)
result.add(i);
k = 0;
map2.clear();
}
return result;
}
public static void main(String[] args)
{
String s = "barfoofoobarthefoobarman";
String[] words = {"bar","foo","the"};
System.out.println(findSubstring(s, words));
}
}
时间复杂度:
设LS为字符串S的长度,N为words中字符串的个数,L为words中字符串的长度。
最坏情况下,判断的S子串的个数为LS-N*L,每个子串都要经过N次的在hashmap中查找。这种情况下,时间复杂度为O(N*(LS-N*L))。
空间复杂度:
由N和解的个数决定。hashmap占用的空间O(N)。