zoukankan      html  css  js  c++  java
  • Substring with Concatenation of All Words leetcode java

    题目:

    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).

     

    题解:

    我最开始做的是说把L里面给的串全排列放起来,看S包含不包含其中之一,包含的话反话其index。但是这个方法TLE了

    代码:

     1    public static void swap(String[] str, int i, int j){  
     2         String temp = new String();  
     3         temp = str[i];  
     4         str[i] = str[j];  
     5         str[j] = temp; 
     6     } 
     7     
     8     public static void arrange (String[] L, int st, ArrayList<String> re){
     9         if (st == L.length - 1){
    10             String temp = new String();
    11             for (int i = 0; i < L.length; i ++){
    12                 temp +=L[i];
    13             }  
    14             re.add(temp);
    15         }else{
    16             for (int i = st; i < L.length; i ++){  
    17                 swap(L, st, i);  
    18                 arrange(L, st + 1,re);  
    19                 swap(L, st, i);  
    20             }  
    21         }  
    22         return ;
    23     }  
    24     public static ArrayList<Integer> findSubstring(String S, String[] L) {
    25         ArrayList<Integer> result = new ArrayList<Integer>();
    26         ArrayList<String> possible = new ArrayList<String>();
    27         arrange(L,0,possible);
    28         
    29         for(int j= 0; j<possible.size();j++){
    30             if(S.contains(possible.get(j)))
    31                 result.add(S.indexOf(possible.get(j)));     
    32         }
    33        
    34         return result;
    35     }

     更好的解法就是一种滑动窗口式的。我是参照了http://blog.csdn.net/linhuanmars/article/details/20342851的写法,他的写法目前速度最快。

     首先是先把所给的字典利用HashMap建一下,key存word,value存这个word出现的个数。

     因为每个单词长度一样,外层循序只许循环wordLen次,每次指针挪一次,每一次循环遍历整个字符串。

     内层循环每次遍历一个单词,把整个S字符串遍历检查。

     需要在每次大循环维护一个count,看是不是达到了给的字典字符串数量,同时维护一个index,是每个符合条件的字符串的起始index,需要存到返回结果中。

     为了能够检查是不是合格字符串,在这里维护一个curDict的HashMap。

     首先检查一个单词是不是在原始字典中出现,没出现的话说明这个单词肯定不符合标准,index指针指向下一个单词的起始点,计数器和curDict都要清零。

     如果这个单词在原始字典里出现过,用更新原始字典的方法更新curDict,如果这个单词出现的次数没有超过原始字典里记录的次数,那么count++,如果超过了,就需要挪动指针,并把超过的从curDict删掉。

     最后,如果count达到了L的length,说明找到了一个合格的字符串,那么将index存入返回结果res中,再把index挪到下一个单词处,更新curDict即可。

    code ganker的讲解是这样的:

    这道题看似比较复杂,其实思路和Longest Substring Without Repeating Characters差不多。因为那些单词是定长的,所以本质上和单一个字符一样。和Longest Substring Without Repeating Characters的 区别只在于我们需要维护一个字典,然后保证目前的串包含字典里面的单词有且仅有一次。思路仍然是维护一个窗口,如果当前单词在字典中,则继续移动窗口右 端,否则窗口左端可以跳到字符串下一个单词了。假设源字符串的长度为n,字典中单词的长度为l。因为不是一个字符,所以我们需要对源字符串所有长度为l的 子串进行判断。做法是i从0到l-1个字符开始,得到开始index分别为i, i+l, i+2*l, ...的长度为l的单词。这样就可以保证判断到所有的满足条件的串。因为每次扫描的时间复杂度是O(2*n/l)(每个单词不会被访问多于两次,一次是窗 口右端,一次是窗口左端),总共扫描l次(i=0, ..., l-1),所以总复杂度是O(2*n/l*l)=O(n),是一个线性算法。空间复杂度是字典的大小,即O(m*l),其中m是字典的单词数量。


    代码部分我自己稍作了修改,主题思想与code ganker相同。

    代码如下:

     1      public static ArrayList<Integer> findSubstring(String S, String[] L) { 
     2          ArrayList<Integer> res = new ArrayList<Integer>();
     3          if(S==null||L==null||S.length()==0||L.length==0)
     4             return res;
     5          int wordLen = L[0].length();//same length for each word in dictionary
     6          
     7          //put given dictionary into hashmap with each word's count
     8          HashMap<String, Integer> dict = new HashMap<String, Integer>();
     9          for(String word: L){
    10              if(!dict.containsKey(word))
    11                 dict.put(word, 1);
    12              else
    13                 dict.put(word, dict.get(word) + 1);
    14          }
    15          
    16          for(int i = 0; i < wordLen; i++){
    17              int count = 0;
    18              int index = i;//index of each startpoint
    19              HashMap<String, Integer> curdict = new HashMap<String, Integer>();
    20              //till the first letter of last word 
    21              for(int j = i; j <= S.length() - wordLen; j += wordLen){
    22                  String curWord = S.substring(j, j + wordLen);
    23                  //check each word to tell if it existes in give dictionary
    24                  if(!dict.containsKey(curWord)){
    25                      curdict.clear();
    26                      count = 0;
    27                      index = j + wordLen;
    28                  }else{
    29                      //form current dictionary
    30                      if(!curdict.containsKey(curWord))
    31                         curdict.put(curWord, 1);
    32                      else
    33                         curdict.put(curWord, curdict.get(curWord) + 1);
    34                      
    35                      //count for current found word and check if it exceed given word count
    36                      if(curdict.get(curWord) <= dict.get(curWord)){
    37                          count++;
    38                      }else{
    39                          while(curdict.get(curWord) > dict.get(curWord)){
    40                              String temp = S.substring(index, index + wordLen);
    41                              curdict.put(temp, curdict.get(temp)-1);
    42                              index = index + wordLen;//make index move next
    43                          }
    44                      }
    45                      
    46                      //put into res and move index point to nextword 
    47                      //and update current dictionary as well as count num
    48                      if(count == L.length){
    49                          res.add(index);
    50                          String temp = S.substring(index, index + wordLen);
    51                          curdict.put(temp, curdict.get(temp)-1);
    52                          index = index + wordLen;
    53                          count--;
    54                      }
    55                  }
    56              }//end for j
    57          }//end for i
    58           return res;
    59         } 

  • 相关阅读:
    Source Insight新建工程文件
    移植3.4.2内核之韦东山笔记
    移植最新u-boot(裁剪和修改默认参数)
    C++与C语言在结构体上的区别
    VIP之Switch
    VIP之CSC
    VIP之Scaler
    VIP之FrameBuffer
    VIP之MixerII
    VIP之Clipper
  • 原文地址:https://www.cnblogs.com/springfor/p/3872516.html
Copyright © 2011-2022 走看看