• [LeetCode-JAVA] 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].

    题意:题意很重要,开始理解错了,以为要求的是words中每个单词出现的index,真正的题意是,words中每一个单词都出现一次,并且中间不夹杂着其他的单词,即word中所有字符串组成的所有可能在s中出现的index。

    思路:建立一个map来维护words的内容,key为words的string,value为对应的数量。 由于words的单词长度相同,因此每次查找的窗口大小一致,为words所有单词的总长度,不用判断边界条件。在判断过程中,建立一个临时的map,来与初始的map进行比较,符合的时候,向list中加入此时的index

    代码:

    public class Solution {
        public List<Integer> findSubstring(String s, String[] words) {
            List<Integer> list = new ArrayList<Integer>();
            if(s == null || s.length() == 0 || words.length == 0)
                return list;
            
            int wordCount = words.length;
            int wordlen = words[0].length();
            int len = wordlen * wordCount;  //总长度
            
            Map<String, Integer> map = new HashMap<String, Integer>();
            Map<String, Integer> cur = new HashMap<String, Integer>();
            
            for(int i = 0 ; i < wordCount ; i++){
                if(!map.containsKey(words[i]))
                    map.put(words[i], 1);
                else
                    map.put(words[i], map.get(words[i])+1);
            }
            boolean flag = true; //标志位
            for(int i = 0 ; i < s.length() - len + 1 ; i++){
                cur.clear(); //循环开始的时候清空上一次的操作
                flag = true;
                for(int j = 0 ; j < wordCount ; j++){
                    String temp = s.substring(i + j*wordlen, i + wordlen*(j+1)); //每一个窗口
                    if(!map.containsKey(temp)){
                        flag = false;
                        break;
                    }
                        
                    if(!cur.containsKey(temp))
                        cur.put(temp, 1);
                    else
                        cur.put(temp, cur.get(temp)+1);
                    
                    if(cur.get(temp) > map.get(temp)){
                        flag = false;
                        break;
                    }
                }
                if(flag) // 如果不是意外break 则内容相符
                    list.add(i);
            }
            return list;
        }
    }

    上面的是自己的思路,不是最快速的,大概是700ms 下面将内外循环换一下 速度提升了一倍 300ms 

    代码:

    public class Solution {
        public static ArrayList<Integer> findSubstring(String S, String[] L) { 
             ArrayList<Integer> res = new ArrayList<Integer>();
             if(S==null||L==null||S.length()==0||L.length==0)
                return res;
             int wordLen = L[0].length();//same length for each word in dictionary
             
             //put given dictionary into hashmap with each word's count
             HashMap<String, Integer> dict = new HashMap<String, Integer>();
             for(String word: L){
                 if(!dict.containsKey(word))
                    dict.put(word, 1);
                 else
                    dict.put(word, dict.get(word) + 1);
             }
             
             for(int i = 0; i < wordLen; i++){
                 int count = 0;
                 int index = i;//index of each startpoint
                 HashMap<String, Integer> curdict = new HashMap<String, Integer>();
                 //till the first letter of last word 
                 for(int j = i; j <= S.length() - wordLen; j += wordLen){
                     String curWord = S.substring(j, j + wordLen);
                     //check each word to tell if it existes in give dictionary
                     if(!dict.containsKey(curWord)){
                         curdict.clear();
                         count = 0;
                         index = j + wordLen;
                     }else{
                         //form current dictionary
                         if(!curdict.containsKey(curWord))
                            curdict.put(curWord, 1);
                         else
                            curdict.put(curWord, curdict.get(curWord) + 1);
                         
                         //count for current found word and check if it exceed given word count
                         if(curdict.get(curWord) <= dict.get(curWord)){
                             count++;
                         }else{
                             while(curdict.get(curWord) > dict.get(curWord)){
                                String temp = S.substring(index, index + wordLen);
                                curdict.put(temp, curdict.get(temp)-1);
                                if(curdict.get(temp)<dict.get(temp)){
                                    count--;
                                }
                                index = index + wordLen;
                            }
                         }
                         
                         //put into res and move index point to nextword 
                         //and update current dictionary as well as count num
                         if(count == L.length){
                             res.add(index);
                             String temp = S.substring(index, index + wordLen);
                             curdict.put(temp, curdict.get(temp)-1);
                             index = index + wordLen;
                             count--;
                         }
                     }
                 }//end for j
             }//end for i
              return res;
            }
    }

    最后自己增加了一些改进 简化了一下代码:

    public class Solution {
        public List<Integer> findSubstring(String s, String[] words) {
            List<Integer> list = new ArrayList<Integer>();
            
            if(s == null || words == null || s.length() == 0)
                return list;
                
            int l = words[0].length();
            int n = words.length;
            int len = l*n;
            
            Map<String, Integer> map = new HashMap<String, Integer>();
            for(int i = 0 ; i < words.length ; i++) {
                if(map.containsKey(words[i])) {
                    map.put(words[i], map.get(words[i]) + 1);
                }else
                    map.put(words[i], 1);
            }
            
            for(int i = 0 ; i < l ; i++) {
                int index = i;  //如果成功的返回值
                int count = 0;  //匹配成功的个数
                Map<String, Integer> tempMap = new HashMap<String, Integer>();
                for(int j = i ; j <= s.length() - l ; j += l) { // 一定要有等号
                    String str = s.substring(j, j + l); //每一个切分
                    if(!map.containsKey(str)) { // 整体右移
                        tempMap.clear();
                        count = 0;
                        index = j + l;  
                    }else {
                        if(!tempMap.containsKey(str)) {
                            tempMap.put(str, 1);
                        }else {
                            tempMap.put(str, tempMap.get(str) + 1);
                        }
                        
                        while(tempMap.get(str) > map.get(str)) { // 循环右移 知道去除最远的相同字符串
                            String left = s.substring(index, index + l); // 窗口最右边的str
                            tempMap.put(left, tempMap.get(left) - 1); // 更新
                            index += l;  // 右移
                            count--;  // 减少一个匹配值
                        }
                        
                        count++;  // 成功匹配到一个
                        
                        if(count == n) { // 全部匹配成功
                            list.add(index);
                        }
                        
                    }
                } // end of for j
            }
            
            return list;
        }
    }

    参考链接:http://www.cnblogs.com/springfor/p/3872516.html

  • 相关阅读:
    定制自己的PHP语法-在PHP中实现unless
    欢迎使用CSDN-markdown编辑器
    在 Laravel 中通过 Artisan View 扩展包创建及删除应用视图文件
    直接可用的loading.js
    vue后退判断是否有历史记录,有就返回上一级,否则返回指定路由
    js防抖和节流
    IE增加Meta标签(IE=Edge,chrome=1)兼容IE问题
    如何覆盖 node_modules 里的文件
    js运行代码计时器
    vue打包font字体文件路径错误的问题处理
  • 原文地址:https://www.cnblogs.com/TinyBobo/p/4555561.html
Copyright © 2020-2023  润新知