zoukankan      html  css  js  c++  java
  • Substring

    【LeetCode】

    LC第30题,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 words exactly 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).

    这道题纠结了大半天,主要是题目要求是O(n)的解法,最容易想到的是下面这种暴力搜索的方法,会超时:

     1 public static List<Integer> findSubstring(String S, String[] L) {
     2     List<Integer> res = new ArrayList<Integer>();
     3     if (S == null || L == null || L.length == 0) return res;
     4     int len = L[0].length(); // length of each word
     5     
     6     Map<String, Integer> map = new HashMap<String, Integer>(); // map for L
     7     for (String w : L) map.put(w, map.containsKey(w) ? map.get(w) + 1 : 1);
     8     
     9     for (int i = 0; i <= S.length() - len * L.length; i++) {
    10         Map<String, Integer> copy = new HashMap<String, Integer>(map);
    11         for (int j = 0; j < L.length; j++) { // checkc if match
    12             String str = S.substring(i + j*len, i + j*len + len); // next word
    13             if (copy.containsKey(str)) { // is in remaining words
    14                 int count = copy.get(str);
    15                 if (count == 1) copy.remove(str);
    16                 else copy.put(str, count - 1);
    17                 if (copy.isEmpty()) { // matches
    18                     res.add(i);
    19                     break;
    20                 }
    21             } else break; // not in L
    22         }
    23     }
    24     return res;
    25 }

    然后发现了大家都会使用的所谓的移动窗口来匹配字符串的方法,这样可以保证复杂度为O(n)。

    基本思路是维护一个窗口,如果当前单词在哈希中,则继续移动窗口右端,否则窗口左端可以跳到字符串下一个单词了。

    而且这里的字符串数组的字符串长度是相同的,所以在写两层循环的时候注意循环停止条件。

     1 class Solution {
     2     public List<Integer> findSubstring(String s, String[] words) {
     3         List<Integer> res = new ArrayList<>();
     4         if(words == null || words.length == 0 || s == null || s.length() == 0)
     5             return res;
     6         int n = s.length(), wcl = words.length;
     7         HashMap<String, Integer> map = new HashMap<>();
     8         for(String word : words)
     9             map.put(word, map.containsKey(word) ? map.get(word) + 1 : 1);
    10         int wl = words[0].length();
    11         for(int i = 0; i < wl; i++){//注意循环终止条件
    12             int left = i, count = 0;
    13             HashMap<String, Integer> tmp = new HashMap<>(); //辅助哈希表
    14             for(int j = i; j <= n - wl; j += wl){
    15                 String str = s.substring(j, j + wl);
    16                 if(map.containsKey(str)){
    17                     if(tmp.containsKey(str))
    18                         tmp.put(str, tmp.get(str)+1);
    19                     else
    20                         tmp.put(str, 1);
    21                     if(tmp.get(str) <= map.get(str))
    22                         count++;
    23                     else{                    //add more word
    24                         while(tmp.get(str) > map.get(str)){
    25                             String str1 = s.substring(left, left + wl);
    26                             if(tmp.containsKey(str1)){
    27                                 tmp.put(str1, tmp.get(str1)-1);
    28                                 if(tmp.get(str1) < map.get(str1))// 只有在小于的时候count--,等于的时候相当于用后面的词替换了前面相同的词,count不变
    29                                     count--;
    30                             }
    31                             left += wl;
    32                         }
    33                     }
    34                     if(count == wcl){
    35                         res.add(left);
    36                         String str2 = s.substring(left, left + wl);  
    37                         if(tmp.containsKey(str2))  
    38                             tmp.put(str2, tmp.get(str2)-1);  
    39                         count--;  
    40                         left += wl; 
    41                     }
    42                 }
    43                 else{
    44                     tmp.clear();
    45                     count = 0;
    46                     left = j + wl;
    47                 }
    48             }
    49         }
    50         return res;
    51     }
    52 }

    一道很类似的题目:76. Minimum Window Substring。

    题目描述:

    Given a string S and a string T, find the minimum window in S which will contain all the characters in T in complexity O(n).

    For example,
    S = "ADOBECODEBANC"
    T = "ABC"
    Minimum window is "BANC".

    Note:
    If there is no such window in S that covers all characters in T, return the empty string "".

    If there are multiple such windows, you are guaranteed that there will always be only one unique minimum window in S.

    模仿上面一道题用两个哈希的写法,结果跑出了倒数10%的成绩。。。

     1 class Solution {
     2     //模仿的Substring with Concatenation of All Words中的解法,用了两个哈希,结果跑了 66 ms。。。
     3     //别人都是用的数组,最快的只有3、4ms。。。
     4     public String minWindow(String s, String t) {
     5         String res = "";
     6         if(s.length() == 0 || t.length() == 0 || s.length() < t.length())
     7             return res;
     8         HashMap<Character, Integer> map = new HashMap<>();
     9         HashMap<Character, Integer> window = new HashMap<>();
    10         for (int i = 0; i < t.length(); i++){
    11             char c = t.charAt(i);
    12             map.put(c, map.containsKey(c) ? map.get(c) + 1 : 1);
    13         }
    14         int minLen = Integer.MAX_VALUE, count = 0;
    15         for(int slow = 0, fast = 0; fast < s.length(); fast++){
    16             char c = s.charAt(fast);
    17             if(map.containsKey(c)){
    18                 if(window.containsKey(c))
    19                     window.put(c, window.get(c) + 1);
    20                 else
    21                     window.put(c, 1);
    22                 if(window.get(c) <= map.get(c))
    23                     count++;
    24             }
    25             if(count == t.length()){
    26                 char cc = s.charAt(slow);
    27                 while(!map.containsKey(cc) || window.get(cc) > map.get(cc)){
    28                     if(window.containsKey(cc))
    29                         window.put(cc, window.get(cc) - 1);
    30                     cc = s.charAt(++slow);
    31                 }
    32                 if(fast - slow + 1 < minLen){
    33                     minLen = fast - slow + 1;
    34                     res = s.substring(slow, slow + minLen);
    35                 }
    36             }
    37         }
    38         return res;
    39     }
    40 }

    事实证明,这个地方用数组就可以解决问题,思想还是一样的移动窗口的思想,事实上,其实这个是子串或者字符串匹配很常用的思想,可以把复杂度降低到O(n)。

    别人跑了4ms的代码:

     1 class Solution {
     2     public String minWindow(String s, String t) {
     3         if (s == "" || t.length() > s.length()) {
     4             return "";
     5         }
     6         int[] map = new int[128];
     7         int start = 0, end = 0, count = t.length(), minStart = 0, minLen = Integer.MAX_VALUE;
     8         for (char ch : t.toCharArray()) {
     9             map[ch]++;
    10         }
    11         while (end < s.length()) {
    12             if (map[s.charAt(end)] > 0) {
    13                 count--;
    14             }
    15             map[s.charAt(end)]--;
    16             end++;
    17             while (count == 0) {
    18                 if (minLen > end - start) {
    19                     minLen = end - start;
    20                     minStart = start;
    21                 }
    22                 map[s.charAt(start)]++;
    23                 if (map[s.charAt(start)] > 0) {
    24                     count++;
    25                 }
    26                 start++;
    27             }
    28         }
    29         return minLen == Integer.MAX_VALUE ? "" : s.substring(minStart, minStart + minLen);
    30     }
    31 }
  • 相关阅读:
    uwsgi启动报错 chdir(): No such file or directory [core/uwsgi.c line 2591]
    Django--导出项目依赖库requirements.txt
    Ubuntu--pip3 -V 问题
    hadoop第一个例子WordCount
    taskTracker和jobTracker 启动失败
    Linux上ln命令详细说明及软链接和硬链接的区别
    myeclipse配置hadoop开发环境
    【hadoop】ssh localhost 免密码登陆(图解)
    net start sshd 发生系统错误1069--cygwin安装过程
    cygwin安装sshd服务(win7)Error installing a service: OpenSCManager: Win32 error 5:
  • 原文地址:https://www.cnblogs.com/niuxichuan/p/7465086.html
Copyright © 2011-2022 走看看