思路:
把所有的子串存入Hashtable,对原字符串进行O(n2)的搜索,看能不能用完Hashtable所有的字串
本题用了不是很好的暴力法压线通过,下次改成用KMP的方法重写一遍。现在还太弱了,不会KMP。。。T^T
还遇到了很奇怪的问题,在代码中注释体现。
package Level3;
import java.util.ArrayList;
import java.util.Hashtable;
/**
* Substring with Concatenation of All Words
* You are given a string, S, and a list of words, L, that are all of the same length. Find all starting indices of substring(s) in S that is a concatenation of each word in L exactly once and without any intervening characters.
For example, given:
S: "barfoothefoobarman"
L: ["foo", "bar"]
You should return the indices: [0,9].
(order does not matter).
*/
public class S30 {
public static void main(String[] args) {
String S = "barfoothefoobarman";
String[] L = {"foo", "bar"};
// String S = "a";
// String[] L = {"a"};
System.out.println(findSubstring(S, L));
}
// 用暴力法压线通过,未来应该用类似KMP的方法降低复杂度!
public static ArrayList<Integer> findSubstring(String S, String[] L) {
ArrayList<Integer> ret = new ArrayList<Integer>();
Hashtable<String, Integer> ht = new Hashtable<String, Integer>();
// 把L中的string全部添加入hashtable
for (String str : L) {
if(ht.containsKey(str)){
ht.put(str, ht.get(str)+1);
}else{
ht.put(str, 1);
}
}
int wordLen = L[0].length();
int numberOfWords = L.length;
// Brute force法比较
for(int i=0; i<=S.length()-numberOfWords*wordLen; i++){
// 每次要基于原hashtable新建一个hashtable
Hashtable<String, Integer> table = new Hashtable<String, Integer>(ht);
int cnt = 0;
// j每次都重复地做相同的工作
for(int j=i; j<=i+numberOfWords*wordLen-wordLen; j+=wordLen){
String substr = S.substring(j, j+wordLen);
if(table.containsKey(substr)){
// 如果只用这一句会TLE
// table.put(substr, table.get(substr)-1);
// 改成这样就能压线AC
int times = table.get(substr);
if(times == 1) table.remove(substr);
else table.put(substr, times - 1);
cnt++;
}else{
break;
}
}
if(cnt == numberOfWords){
ret.add(i);
}
}
return ret;
}
}
KMP的初步认识: http://www.ruanyifeng.com/blog/2013/05/Knuth%E2%80%93Morris%E2%80%93Pratt_algorithm.html
一个基于KMP的解决方法:http://n00tc0d3r.blogspot.com/2013/06/substring-with-concatenation-of-all.html
import java.util.*;
public class Solution {
public List<Integer> findSubstring(String S, String[] L) {
List<Integer> ret = new ArrayList<Integer>();
int m = L.length;
if(m == 0) {
return ret;
}
int n = L[0].length();
Hashtable<String, Integer> ht = new Hashtable<String, Integer>();
for(String word : L) {
Integer cnt = ht.get(word);
if(cnt == null) {
ht.put(word, 1);
} else {
ht.put(word, cnt+1);
}
}
for(int i=0; i<=S.length()-n*m; i++) {
Hashtable<String, Integer> tmp = new Hashtable<String, Integer>();
int j = 0;
for(j=0; j<m; j++) {
int k = i + j*n; // n-characters interval
String substr = S.substring(k, k+n);
Integer cntInHt = ht.get(substr); // check if substr in Hashtable
Integer cntInTmp = tmp.get(substr); // check if substr in temporary Ht
// must be in the original Hashtable and found cnts of character should be less than all available characters
if(cntInHt != null && (cntInTmp == null || cntInTmp < cntInHt)) {
if(cntInTmp == null) {
tmp.put(substr, 1);
} else {
tmp.put(substr, cntInTmp+1);
}
} else {
break;
}
}
if(j == m) { // found all words in L
ret.add(i);
}
}
return ret;
}
}