Friday, February 7, 2014

Leetcode: 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).
Solution:
First we process the list of words into a hashtable that points each word to the possitions in the list of words. This is done in O(n). Then we create a window of size $L\cdot \text{wordSize}$ that we make it advance each time by wordSize, this way each time a candidate word leaves the window and a candidate word enters it. Each word can be removed or added in O($\text{wordSize}$). This makes the total running time O($L+ \text{wordSize} n$) = O(L+n).


public class Solution {
    public ArrayList<Integer> findSubstring(String S, String[] L) 
    {
        if (L.length==0 || S.length()==0)
            return null;
         
         ArrayList<Integer> solution = new ArrayList<Integer>();

        //Preprocess the words into the map
        HashMap<String,ArrayList<Integer>> map = new HashMap<String,ArrayList<Integer>>();
        for(int i=0; i<L.length; i++)
        {
            if(map.containsKey(L[i]))
            {
                ArrayList<Integer> temp = map.get(L[i]);
                temp.add(i);
            }
            else
            {
                ArrayList<Integer> temp = new ArrayList<Integer>();
                temp.add(i);
                map.put(L[i], temp);
            }
        }
        
        int size = L[0].length(); 
        //the windows advance by size, so have to repeat it size times to obtain all the possible windows
        for(int i=0; i<size; i++)
        {
            int found[]=new int[L.length];
            int wordsFound=0;
            for(int j=0; j<(S.length()-i)/size; j++)
            {
                //Remove the word that goes out of the window
                if(j>=L.length)
                {
                    String temp = S.substring((j-L.length)*size+i,i+(j-L.length)*size+size);
                    if(map.containsKey(temp))
                    {
                        if(found[map.get(temp).get(0)]--<=map.get(temp).size())
                            wordsFound--;
                    }
                }
                
                //Adding the new word to the window
                String temp = S.substring(j*size+i,i+j*size+size);
                if(map.containsKey(temp))
                {
                    if(found[map.get(temp).get(0)]++ < map.get(temp).size())
                        wordsFound++;
                }

                //Check if the window has all the words
                if(wordsFound==L.length)
                    solution.add((j-L.length+1)*size+i);
            }
        }
        return solution;
    }
}

No comments :

Post a Comment