import java.util.*; /** * 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). * * Tags: Hash Table, Two Pointers, String */ class SubstringWithConcatOfAllWords { public static void main(String[] args) { String S = "barfoothefoobarman"; String[] L = new String[]{"foo", "bar"}; List<Integer> l = findSubstring(S, L); for (int i : l) System.out.print(i + " "); } /** * Build a map for words in L and its relative counts */ public static List<Integer> findSubstring(String S, String[] L) { List<Integer> res = new ArrayList<Integer>(); if (S == null || L == null || L.length == 0) return res; int len = L[0].length(); // length of each word Map<String, Integer> map = new HashMap<String, Integer>(); // map for L for (String w : L) map.put(w, map.containsKey(w) ? map.get(w) + 1 : 1); for (int i = 0; i <= S.length() - len * L.length; i++) { Map<String, Integer> copy = new HashMap<String, Integer>(map); for (int j = 0; j < L.length; j++) { // check if match String str = S.substring(i+j*len, i+j*len+len); // next word if (copy.containsKey(str)) { // is in remaining words int count = copy.get(str); if (count == 1) copy.remove(str); else copy.put(str, count - 1); if (copy.isEmpty()) { // matches res.add(i); break; } } else break; // not in L } } return res; } }