20210510力扣第30题:串联所有单词的子串

1.题目

给定一个字符串 s 和一些长度相同的单词 words。找出 s 中恰好可以由 words 中所有单词串联形成的子串的起始位置。

注意子串要与 words 中的单词完全匹配,中间不能有其他字符,但不需要考虑 words 中单词串联的顺序。

来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/substring-with-concatenation-of-all-words
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

输入:
  s = "barfoothefoobarman",
  words = ["foo","bar"]
输出:[0,9]
解释:
从索引 09 开始的子串分别是 "barfoo""foobar" 。
输出的顺序不重要, [9,0] 也是有效答案。




输入:
  s = "wordgoodgoodgoodbestword",
  words = ["word","good","best","word"]
输出:[]



2.想法

想法1:
自己看到这道题开始没什么思路,所以想到的还是暴力破解的方法,尝试着用两个for遍历一下word,将word的每种顺序都储存在一个string的List中,最后再用string的方法indexof去寻找是否包含数组中的方法。
结果:只有测试案例的word是两个元素时才可以,有的还不行,所以这样的方法行不通,如果是4个,五个,两个for循环是不行了;
也把自己写的这个简单程序放在这里:

class Solution {
    public List<Integer> findSubstring(String s, String[] words) {
      ArrayList<String> list = new ArrayList<String> ();

      for(String s1:words)
      {
          for(String s2:words)
          {
              if(s1!=s2)
              {
                  String s3 = s1+s2;
                  list.add(s3);
              }
          }
      }  


       List<Integer> intList = new ArrayList<>();
       for(String s4 :list)
       {
           int count = s.indexOf(s4);
           if(count!= -1) intList.add(count);
           
       }
       return intList;
    }
}

想法2:
根据想法1,就是word组合的情况不如意,所以,尝试着写一个方法,两两字符串组合,但是for迭代下来是有顺序的,所以这种无顺序的储存写起来可能还是有问题。而且里面存在重复元素,重复元素的处理也得重新写代码,所以需要用到无序的数据结构了,看了下评论,大多用的是hashmap。

想法3:
这个想法是看评论区的:

  • 计算一个单词的长度,计算word的长度,相乘得到最后拼接的总长度。
  • 将word的元素都放入hashMap中。

举个例子吧s长度为10,word有两个一个长度是3;那么总长为2*3=6;那么其实我们只需要看s的前四个字母就好,一个长度是6,看前四个(进入这个循环)在进行比较,如(0+6)(1+6)(2+6)(3+6)这样就是一个滑动窗口。
在滑动过程中,再建一个map,然后逐个把单词放入map中,最后比较这个map和开始的hashmap是否相等,相等的话,那么就把这个位置(0 1 2 3 )加入IntList返回

3.代码

class Solution {
    public List<Integer> findSubstring(String s, String[] words) {
      ArrayList<Integer> res = new ArrayList<> ();

      int word1_Len = words[0].length();
      int words_Len = words.length; 
      int all_len = word1_Len*words_Len;//总长度

      Map<String,Integer> map = new HashMap<>();
      for(String word:words)
      {
          map.put(word,map.getOrDefault(word,0)+1);
      }
      //这里之前都是 把 单词放入map中 接下来开始窗口移动
      for(int i = 0 ; i<s.length()-all_len+1;i++)
      {
          String temp = s.substring(i,i+all_len);//temp 就是一个窗口
          Map<String,Integer> temp_map = new HashMap<>();
          for(int j = 0 ;j<all_len;j+=word1_Len)//开始遍历单词 注意j+=word1_len
          {
              String s2 =temp.substring(j,j+word1_Len);
              temp_map.put(s2,temp_map.getOrDefault(s2,0)+1);
          }
          if(map.equals(temp_map)) res.add(i);
      }

      return res;
    }
}

再总结一下这个代码,毕竟是看评论区才写出来的。
先计算一个单词的长度,在计算word的长度,最后得知拼接的总长度,现在将这些word放入hashmap中。
下来开始滑动窗口,滑动窗口中,获取临时字符串。
在临时字符串中,获取一个单词的字符串,将这一个单词的字符串放入map中,最后比较map与开始的hashmap,返回。

总结

这道题自己的想法太简单,这种不按顺序的需要用到hashmap就直接使用,自己见到这样的题反而有些害怕用,只是一个数据结构,放心大胆的俑,额能比自己已知的那些本方法好很多,不要见了就害怕,还有本题中的map.getOrDefault方法是获取值,若没有就获取默认值。

	如map.getOrDefault(score,0);没有score就是0分,有就获取。

自己还有一点没有明白的是.

temp_map.put(s2,temp_map.getOrDefault(s2,0)+1);

最后+1,这如果不+1就会运行出错,这是为什么呢?


版权声明:本文为duan18291953965原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明。