package com.interview.leetcode.strings;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
/**
* Created_By: stefanie
* Date: 14-11-17
* Time: 下午1:35
* You are given a string, S, and a list of words, L, that are all of the same length. (L are same length simplify the problem)
* 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).
*
* Solutions: similar like {@link MinWindowSubstring}
* 1. create a hashmap of all words in L
* 2. scan S from 0 ~ length - L.totalLength()
* every time get a word, check if exist in L, if yes, count it, if no break
* check the count, if count is larger than in L, break
* if found all the words, mark current i if a position
*
* Tricks:
* 1. use a HashMap for string matching problem.
*/
public class ConcatenationSubString {
public static List<Integer> findSubstring(String S, String[] L) {
ArrayList<Integer> result = new ArrayList<Integer>();
HashMap<String, Integer> expected = new HashMap<String, Integer>();
HashMap<String, Integer> found = new HashMap<String, Integer>();
int m = L.length; int n = L[0].length();
for(int i = 0; i < m; i++){
if(!expected.containsKey(L[i])) expected.put(L[i], 1);
else expected.put(L[i], expected.get(L[i]) + 1);
}
for(int i = 0; i <= S.length() - n * m; i++){
found.clear();
int j = 0;
for(j = 0; j < m; j++){
int k = i + j * n;
String str = S.substring(k, k + n);
if(expected.get(str) == null) break; //contains a word doesn't expected
if(!found.containsKey(str)) found.put(str, 1);
else found.put(str, found.get(str) + 1);
if(found.get(str) > expected.get(str)) break; //word count found is larger than expected
}
if(j == m) result.add(i); //found all the word
}
return result;
}
}