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

    问题:给定一个字符串 s 和 一列单词 words 。找出 s 中所有满足下面条件的全部子字符串的开始下标:要求子字符串恰好由 words 的所有单词拼接而成,每个单词仅对应地出现一次。

    由于 words 里面单词是无序的,目标子字符串的成员单词也是无序的,所以,考虑用 Hashtable 作为数据存储。

    需要充分利用的两个题目条件:

    1. 所有单词等长

    2. 目标子字符串是由单词连续无中断地连接而成

    根据上面两个条件,可以将 s 全部分割为长度为 length 的子字符串,共有 length 种分法。length 种分法会覆盖全部需要找的子字符串

    对于每一种分割,可以将长度为 length 的子字符串视为不再分割的单元,利用滑动窗口算法(Slide Window Algorithm),线性时间找到符合条件的目标子字符串,O(n/length) 复杂度,其中 n 为 s 的长度。一共有 length 种分发,则耗时 O(length * n/length) = O(n)。

    算法实现思路

    将 s 全部分割为长度为 length 的连续子串的方法,一共有 length 种。

    对于每一种 k (0 <= k < length, 表示开始分割的起始下标 ) 有:

      以 k 为起始位置,长度为 length 子字符串即为一个待验证子串 subs

      左右指针指向首个 subs 

      若右指针指向的 subs 是要找的 word, 并且已记录的次数小于需要找到的次数,则记录新找到一个 subs,右指针右移

      若右指针指向的 subs 是要找的 word,并且已记录的次数等于需要找到的次数, 则将左指针当前单词从记录中排除,并左指针右移,重复此操作直到从记录中排除一个右指针当前的 subs。使得 [ subs 已记录的次数小于需要找到的次数 ]。

      若右指针指向的 subs 不是要找的 word,则右指针右移,左指针指向右指针位置,并情况记录。

      若已找到的记录(左右指针内元素)恰好等于需要找到全部 words ,则保存左指针所在位置,即为一个需要找的下标。然后,将左指针当前元素从记录中排除,左指针右移。

    实现代码

    import java.util.Hashtable;
    import java.util.LinkedList;
    import java.util.List;
    import java.util.Map.Entry;
    import java.util.Set;
    
    class Utility{
        
        /**
         * reset the value of matched result str_cnt_mch 
         * 
         * @param str_cnt_mch
         */
        public static void resetHashtable(Hashtable<String, Integer> str_cnt_mch){
            Set<Entry<String, Integer>> set = str_cnt_mch.entrySet();
            for (Entry<String, Integer> s_c : set){
                s_c.setValue(0);
            }
        }
    }
    
    public class Solution {
    public List<Integer> findSubstring(String s, String[] words) { List<Integer> res = new LinkedList<Integer>(); Hashtable<String, Integer> str_cnt = new Hashtable<String, Integer>(); Hashtable<String, Integer> str_cnt_mch = new Hashtable<String, Integer>(); for (String wrd : words) { if (str_cnt.containsKey(wrd)) { str_cnt.put(wrd, str_cnt.get(wrd) + 1); } else { str_cnt.put(wrd, 1); } str_cnt_mch.put(wrd, 0); } int length = words[0].length(); for (int k = 0; k < length; k++) { int lft = k; int rgh = k; Utility.resetHashtable(str_cnt_mch); int mchCnt = 0; while (rgh + length <= s.length()) { String subs = s.substring(rgh, rgh + length); if (str_cnt.containsKey(subs)) { if (str_cnt_mch.get(subs) < str_cnt.get(subs)) { str_cnt_mch.put(subs, str_cnt_mch.get(subs) + 1); mchCnt++; rgh += length; } else { // the number of subs in str_cnt_mch is the same as that // in str_cnt while (true) { String subsl = s.substring(lft, lft + length); str_cnt_mch.put(subsl, str_cnt_mch.get(subsl) - 1); mchCnt--; lft +=length; if (subsl.equals(subs)) { break; } } } } else { // subs is not a word in words Utility.resetHashtable(str_cnt_mch); mchCnt = 0; rgh = rgh + length; lft = rgh; } if (mchCnt == words.length){ res.add(lft); String subsl = s.substring(lft, lft + length); str_cnt_mch.put(subsl, str_cnt_mch.get(subsl) - 1); mchCnt--; lft = lft + length; } } } return res; } }

    参考资料:

     Substring with Concatenation of All Words -- LeetCode, Code_Ganker, CSDN

  • 相关阅读:
    HTML-DOM实例——实现带样式的表单验证
    HTML-DOM常用对象的用法(select/option/form/table)
    class介绍
    let 和const命令
    页面滚动事件和利用JS实现回到顶部效果
    DOM的利用冒泡做的一个小程序
    BOM的对象总结(location,screen,navigator,history)
    IE下的双外边距浮动bug
    全国计算机三级网络工程技术复习笔记2
    全国计算机三级网络工程技术复习笔记1
  • 原文地址:https://www.cnblogs.com/TonyYPZhang/p/5491719.html
Copyright © 2020-2023  润新知