• LeetCode 笔记系列七 Substring with Concatenation of All Words


    题目: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).

    这道题想了蛮久,主要是coding过程中老是出一些边界的错误。第一眼看到,立(zi)马(zuo)想(cong)到(ming)的解法是不是可以用bit位来表示L中的各个key呀,不同的key代表不同的位,然后通过扫描S,通过与操作确定各个bit位是不是在长度为L的substring中。结果写了一会发现问题是,L中有可能有相等的字符串哦。。。那在搜索S的时候就悲剧了不是。

    一个折中的方法是,对每个key在L中的,保存一个list,例如有L=["foo","bar","foo"],那我们做这样一个hash哇:

    foo: 0->1

    bar: 2

    然后在搜索S的时候顺次检查一个bitset。代码如下:

    解法一:

     1 public static ArrayList<Integer> findSubstring2(String S, String[] L) {
     2         int lengthPerKey = L[0].length();
     3         int numberOfKeys = L.length;
     4         BitSet bitSet = new BitSet(numberOfKeys);
     5         HashMap<String, ArrayList<Integer>> map = new HashMap<String, ArrayList<Integer>>();
     6         ArrayList<Integer> result = new ArrayList<Integer>();
     7         int k = 0;
     8         for(String str : L){
     9             if(!map.containsKey(str)){
    10                 ArrayList<Integer> list = new ArrayList<Integer>();
    11                 list.add(k++);
    12                 map.put(str, list);
    13             }else {
    14                 map.get(str).add(k++);
    15             }
    16         }
    17         
    18         for(int i = 0; i <= S.length() - numberOfKeys*lengthPerKey; i++){
    19             bitSet.clear();
    20             int j = 0;
    21             int st = i;
    22             for(j = 0; j < numberOfKeys;j++){
    23                 if(S.length() - st < (numberOfKeys - j)*lengthPerKey) break;
    24                 ArrayList<Integer> list = map.get(S.substring(st, st + lengthPerKey));
    25                 if(list == null)break;
    26                 k = 0;
    27                 while(k < list.size() && bitSet.get(list.get(k))) k++;
    28                 if(k < list.size())
    29                     bitSet.set(list.get(k));
    30                 else break;
    31                 st += lengthPerKey;
    32             }
    33             if(bitSet.cardinality() == numberOfKeys) {
    34                 result.add(i);
    35             }
    36         }
    37         return result;
    38     }
    View Code

    不幸的是,大集合超时了。我去。。。

    仔细想想,非要用bitset么?特别是扫描的inner loop,还要遍历hash的value(list)。完全可以用一个计数代替么。不用遍历list,对于重复出现的,我们search S的时候,只是减去计数1.

    解法二:

     1 public static ArrayList<Integer> findSubstring3(String S, String[] L) {
     2         int lengthPerKey = L[0].length();
     3         int numberOfKeys = L.length;
     4         HashMap<String, Integer> map = new HashMap<String, Integer>();
     5         ArrayList<Integer> result = new ArrayList<Integer>();
     6         for(String str : L){
     7             if(!map.containsKey(str)){
     8                 map.put(str, 1);
     9             }else {
    10                 map.put(str, map.get(str) + 1);
    11             }
    12         }
    13         
    14         for(int i = 0; i <= S.length() - numberOfKeys*lengthPerKey; i++){
    15             int j = 0;
    16             int st = i;
    17             HashMap<String, Integer> wordsCount = new HashMap<String, Integer>(map);
    18             for(j = 0; j < numberOfKeys;j++){
    19                 if(S.length() - st < (numberOfKeys - j)*lengthPerKey) break;
    20                 String sub = S.substring(st,st+lengthPerKey);
    21                 if(wordsCount.containsKey(sub)){
    22                     int times = wordsCount.get(sub);
    23                     if(times == 1) wordsCount.remove(sub);
    24                     else wordsCount.put(sub, times - 1);
    25                 }else break;
    26                 st += lengthPerKey;
    27             }
    28             if(j == numberOfKeys){
    29                 result.add(i);
    30             }
    31         }
    32         return result;
    33     }
    View Code

    例如L=["foo","bar","foo"],我们的hash是这样的:

    foo: 2

    bar: 1

    然后对S中每一个固定长度的substring做计数。

    总结:

    1.如果你用了超过3个(包括3个)复杂数据结构,应该思考是不是自己想多了

    2.想多了会了你。

    3.不要装b,先理解问题再想解法而不是为了用某个算法。

  • 相关阅读:
    [APIO2017] 商旅
    [SDOI2017] 新生舞会
    FileUtils类介绍
    经典算法面试题目-设计算法移除字符串中重复的字符(1.3)
    Web---演示Servlet的相关类、表单多参数接收、文件上传简单入门
    Java新手入门必须掌握的30个基本概念
    你需要知道的10位Java开发牛人
    Web---演示Servlet的相关类、下载技术、线程问题、自定义404页面
    经典算法面试题目-翻转一个C风格的字符串(1.2)
    Web---创建Servlet的3种方式、简单的用户注册功能
  • 原文地址:https://www.cnblogs.com/lichen782/p/leetcode_SubstringwithConcatenationofAllWords.html
Copyright © 2020-2023  润新知