LeetCode 30 Substring with Concatenation of All Words 解法为Hashmap

Substring with Concatenation of All Words

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 wordsexactly once and without any intervening characters.

For example, given:
s"barfoothefoobarman"
words["foo", "bar"]

You should return the indices: [0,9].
(order does not matter).

解题思路:首先,理解题意很重要。由于我之前没有理解题意,靠测试用例理解,走了不少弯路。题意是返回字符串中的字符串片段,这样的组合涵盖words数组的每个字符串。若words中包含重复项,字符串组合中也应当有重复项。比如:wordgoodgoodgoodbestword,{"word","good","best","good"}  返回 8,就是从第8个起的子串涵盖words数组。

在这里,得以复习hashmap,并利用数组条件,减少使用map接口的频率,从而降低时间消耗。

由于存在重复项的问题,为此,我们设立两个map,一个记录words的字符串出现次数,一个作为临时map,记录每次截取的字符串个数。若出现不是第一个map的子串则跳过,若扫描个数出现大于第一个map的个数则跳过。若完成遍历的时候,计数与words长度相同,不需要map的相等判断,直接可以判断符合条件。因为,不符合的情况,已经全部被过滤。

public List<Integer> findSubstring(String s, String[] words) {
		 int len = s.length();
		 int wlen = words.length;
		 int slen =words[0].length();
		 int end = len-wlen*slen;
		 //判断是否都满足子串数组
		 HashMap<String, Integer> map = new HashMap<String, Integer>();
		 HashMap<String, Integer> map1 = new HashMap<String, Integer>();//临时map
		 List<Integer> ls =new ArrayList<Integer>();
		 for (int i = 0; i < wlen; i++) {
			 if(map.containsKey(words[i])){
				 map.put(words[i], map.get(words[i])+1);
			 }else{
				 map.put(words[i], 1); 
			 }
		}
		 int i=0;
		 while(i<=end){
			 String str = s.substring(i, i+slen);
				if(map.containsKey(str)){
					//判断满足出现的组合contain
					 if(map1.containsKey(str)){
						 map1.put(str, map1.get(str)+1);
					 }else{
						 map1.put(str, 1); 
					 }
					int t =i+slen;
					int j;
                  for ( j = 1; j < wlen; j++) {
                	  if(t+slen>len){
                		  return ls;
                	  }
                	  String str1 = s.substring(t, t+slen);
                	  if(map.containsKey(str1)){
                		  if(map1.containsKey(str1)){
     						 map1.put(str1, map1.get(str1)+1);
     					 }else{
     						 map1.put(str1, 1); 
     					 }	  
                	  }else{
                		  break;
                	  }
                	  t+=slen;
                	  if(map1.get(str1)>map.get(str1)){//这个
                		  break;
                	  }
				}
            	  if(j==wlen){//这个
                	  ls.add(i);
                  }
			}
		i++;
  	  map1.clear();
		 }
		return ls;     
	    }

上述对算法的优化参考自http://www.cnblogs.com/zhaolizhen/p/SubCon.html

这里,再给出一个discuss上的O(n)的解法:

public List<Integer> findSubstring(String S, String[] L) {
    List<Integer> res = new ArrayList<>();
    if (L.length == 0) {
        return res;
    }
    int len = L[0].length();
    int num = L.length;
    if (len * num > S.length()) {
        return res;
    }

    //histogram of words in L
    HashMap<String, Integer> dic = new HashMap<>();
    for (String s : L) {
        if (dic.containsKey(s)) {
            dic.put(s, dic.get(s) + 1);
        } else {
            dic.put(s, 1);
        }
    }

    //the word that starts from i in S
    String[] sDic = new String[S.length() - len + 1];
    for (int i = 0; i < sDic.length; i++) {
        String sub = S.substring(i, i + len);
        if (dic.containsKey(sub)) {
            sDic[i] = sub;
        } else {
            sDic[i] = "";
        }
    }

    //traverse in order of 0,0+len,...,1,1+len,...len-1,len-1+len...therefore it is O(n) despite of two loops
    for (int i = 0; i < len; i++) {

        //start of concatenation
        int start = i;
        //number of words found
        int found = 0;
        //dynamic word histogram of words in substring(start,j);
        HashMap<String, Integer> tempDic = new HashMap<>();
        for (int j = i; j <= S.length() - len; j = j + len) {
            String word = sDic[j];
            if (word.equals("")) {
                tempDic = new HashMap<>();
                start = j + len;
                found = 0;
                continue;
            } else {
                if (!tempDic.containsKey(word)) {
                    tempDic.put(word, 1);
                } else {
                    tempDic.put(word, tempDic.get(word) + 1);
                }
                found++;
            }
            //if we over-count a word, delete the first word in front. Also delete the words before that.
            if (tempDic.get(word) > dic.get(word)) {
                while (!sDic[start].equals(word)) {
                    tempDic.put(sDic[start], tempDic.get(sDic[start]) - 1);
                    start += len;
                    found--;
                }
                tempDic.put(word, tempDic.get(word) - 1);
                start += len;
                found--;
            }
            if (found == num) {
                res.add(start);
            }

        }

    }
    return res;
}


你可能感兴趣的:(LeetCode 30 Substring with Concatenation of All Words 解法为Hashmap)