LeetCode – Substring with Concatenation of All Words (Java)

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"], return [0,9].

Analysis

This problem is similar (almost the same) to Longest Substring Which Contains 2 Unique Characters.

Since each word in the dictionary has the same length, each of them can be treated as a single character.

Java Solution

public List<Integer> findSubstring(String s, String[] words) {
    ArrayList<Integer> result = new ArrayList<Integer>();
    if(s==null||s.length()==0||words==null||words.length==0){
        return result;
    } 
 
    //frequency of words
    HashMap<String, Integer> map = new HashMap<String, Integer>();
    for(String w: words){
        if(map.containsKey(w)){
            map.put(w, map.get(w)+1);
        }else{
            map.put(w, 1);
        }
    }
 
    int len = words[0].length();
 
    for(int j=0; j<len; j++){
        HashMap<String, Integer> currentMap = new HashMap<String, Integer>();
        int start = j;//start index of start
        int count = 0;//count totoal qualified words so far
 
        for(int i=j; i<=s.length()-len; i=i+len){
            String sub = s.substring(i, i+len);
            if(map.containsKey(sub)){
                //set frequency in current map
                if(currentMap.containsKey(sub)){
                    currentMap.put(sub, currentMap.get(sub)+1);
                }else{
                    currentMap.put(sub, 1);
                }
 
                count++;
 
                while(currentMap.get(sub)>map.get(sub)){
                    String left = s.substring(start, start+len);
                    currentMap.put(left, currentMap.get(left)-1);
 
                    count--;
                    start = start + len;
                }
 
 
                if(count==words.length){
                    result.add(start); //add to result
 
                    //shift right and reset currentMap, count & start point         
                    String left = s.substring(start, start+len);
                    currentMap.put(left, currentMap.get(left)-1);
                    count--;
                    start = start + len;
                }
            }else{
                currentMap.clear();
                start = i+len;
                count = 0;
            }
        }
    }
 
    return result;
}
Category >> Algorithms >> Interview  
If you want someone to read your code, please put the code inside <pre><code> and </code></pre> tags. For example:
<pre><code> 
String foo = "bar";
</code></pre>
  • Ahmad El-Qaoud

    I solved by a better solution which happens to be more clear and has a better performance using the indexOf method and comparing the indices as follows:

    public static List searchIndecies(String s, String arr[]) {

    if (s == null || s.length() == 0 || arr == null || arr.length == 0) {
    return null;
    }
    int wordLength = arr[0].length();
    List returnedIndecies = new ArrayList();
    List indecies = new ArrayList();
    for (int i = 0; i < s.length(); i++) {
    indecies.clear();
    for (int m = 0; m < arr.length; m++) {
    int index = s.indexOf(arr[m], i);
    if (index != -1) {
    indecies.add(index);
    }
    }
    Collections.sort(indecies);
    boolean validSeq = false;
    for (int n = 1; n < indecies.size() && indecies.size() == arr.length; n++) {
    if (indecies.get(n – 1) != indecies.get(n) – wordLength) {//Comparing indices based on words same length
    i = i + wordLength – 1;
    break;
    } else {
    i = indecies.get(n);
    validSeq = true;
    }
    }
    if (validSeq) {
    returnedIndecies.add(indecies.get(0));
    }

    }
    return returnedIndecies;

    }

  • Larry Okeke

    A simple to understand soluton.

    Just get every possible concatenation of words in words array, and check whether each occurs in the main string.
    if the result is not -1, we have an index of substring!

    import java.util.*;

    public class duplicate_substring{

    public static ArrayList allPossibleArrangements = new ArrayList();

    public static void main(String[] args){

    String[] arr = new String[] {"chinelo", "arukwe", "larry"};

    ArrayList words = new ArrayList(Arrays.asList(arr));

    String s = "chineloarukwelarryokekearukwechinelolarrytestinglarryarukwechinelo";

    permutate(words, new Stack(), arr.length);

    List solution = solution(allPossibleArrangements.toArray(new String[0]), s);

    System.out.println(solution.toString());

    }

    public static List solution(String[] words, String s){

    //use combinatorial algorithm to get every possible concatenation of words

    //find the index of each derived word in s.

    StringBuilder build = new StringBuilder();

    ArrayList result = new ArrayList();

    for(int i = 0; i < words.length; i++){

    String currentConcatenation = words[i];

    if(s.indexOf(currentConcatenation)!=-1){

    result.add(s.indexOf(currentConcatenation));

    }

    build.setLength(0);

    }

    return result;

    }

    public static void permutate(List items, Stack permutation, int size) {

    /* permutation stack has become equal to size that we require */

    if(permutation.size() == size) {

    /* print the permutation */

    //System.out.println(Arrays.toString(permutation.toArray(new Integer[0])));

    String s = "";

    for(String str: permutation){

    s+=str;

    }

    allPossibleArrangements.add(s);

    }

    /* items available for permutation */

    String[] availableItems = items.toArray(new String[0]);

    for(String i : availableItems) {

    /* add current item */

    permutation.push(i);

    /* remove item from available item set */

    items.remove(i);

    /* pass it on for next permutation */

    permutate(items, permutation, size);

    /* pop and put the removed item back */

    items.add(permutation.pop());

    }

    }

    }