leetcode 30. 串联所有单词的子串(优质解法)

代码:

java 复制代码
class Solution {
    public static List<Integer> findSubstring(String s, String[] words) {
        List<Integer> integerList=new ArrayList<>();

        int length=words.length;    //words 数组中的字符串个数
        int size=words[0].length(); //words 数组中每个字符串的长度

        HashMap<String,Integer> hashMap1=new HashMap<>();   //存储 words 数组中字符串以及出现的个数


        //把 words 数组中字符串以及出现的个数保存到 hashMap1 中
        for(String str:words){
            hashMap1.put(str,hashMap1.getOrDefault(str,0)+1);
        }

        for(int i=0;i<size;i++){
            int count=0;    //记录当前子串中符合条件的字符串
            HashMap<String,Integer> hashMap2=new HashMap<>();   //存储讨论的子串中字符串以及出现的个数
            for(int left=i,right=i;right+size<=s.length();right+=size){
                //把 right 指针指向的数据入窗口
                String in=s.substring(right,right+size);
                hashMap2.put(in,hashMap2.getOrDefault(in,0)+1);

                //判断当前入窗口的字符串是否是符合条件的
                if(hashMap2.get(in)<=hashMap1.getOrDefault(in,0)){
                    count++;
                }

                //判断当前子串的长度是否过长,是否需要出窗口
                if(right-left+1>length*size){
                    String out=s.substring(left,left+size);
                    //判断出窗口的字符串是否是有效字符串
                    if(hashMap2.get(out)<=hashMap1.getOrDefault(out,0)){
                        count--;
                    }
                    hashMap2.put(out,hashMap2.get(out)-1);
                    left+=size;
                }

                //判断有效字符串个数是否符合条件
                if(count==length){
                    integerList.add(left);
                }
            }
        }
        return integerList;
    }
}

题解:

本题的含义表达得很明确,我们需要在字符串 s 中找到一个子串,子串由字符串数组 words 中的字符串以不同顺序组成

我们首先可以想到一个暴力解法,遍历出字符串 s 中的所有子串,找出完全由 words 中的字符串以不同顺序组成的子串。现在就涉及到一个问题,我们如何知道子串是完全由 words 中的字符串以不同顺序组成的

我们可以利用哈希表 hash1 和 hash2 存储 words 数组中和子串中字符串的相关信息,以字符串为 key ,个数为 value ,然后比对 hash1 和 hash2 中的内容,便知道当前子串是否是符合条件的

假设**输入:**s = "barfoothefoobar", words = ["foo","bar"]

首先我们可以获得的信息是,words 数组中的字符串个数 length = 2,每个字符串的大小 size = 3 ,由于我们要遍历所有的子串,所以让 L 和 R 指针指向下标为 0 的位置。我们将 words 数组中的相关信息保存到哈希表 hash1 中,foo-1,bar-1,用变量 count 记录子串中有效字符串的个数

因为符合要求的子串是由 words 数组中的字符串按不同顺序组成的,而 words 数组中的字符串是 3 个字符为一个整体,所以我们在寻找子串的时候也以 3 个字符为一个整体,R 指针指向当前位置,通过 s.substring(right,right+size) 取出字符串 bar,将 bar - 1 保存到 hash2 中,由于在hash1 中 bar-1,只要子串中的字符个数小于等于 wors 数组中对应字符的个数,就代表该字符是有效字符,所以 bar 是有效字符,此时 count++,count=1

b a r f o o t h e f o o b a r

L

R

录入字符串 bar 的信息以后,R 指针向右移动 size 位,录入下一个字符串 foo,将 foo- 1 保存到 hash2 中,由于在hash1 中 foo-1,,所以 foo 是有效字符,此时 count++,count=2,因为此时子串为 barfoo 长度为 6 == size*length ,并且 count == 2 == length,所以该子串是符合要求的,我们就直接记录 L 指针指向的下标 0

b a r f o o t h e f o o b a r

L

R

当 R 指针再向右移 size 位以后,子串为 barfoothe,大小为 9 > size * length ,字符数都比 words 数组中的字符数多了,肯定不符合要求,代表以 L 指针为首的子串已经讨论完毕,让 L 指针向右移动 size 位,讨论下一组字符串

b a r f o o t h e f o o b a r

L

R

L 指针之前指向的是字符串 bar ,bar 在 hash2 中的个数为 1,小于等于在 hash1 中的个数,所以是有效字符串,因此在将 L 指针移动前,我们需要修改 hash2 中的 bar - 0,count = 1,

此时子串的长度符合要求,但是有效字符串个数 count < length,所以该子串不符合要求,让 R 指针向右移动 size 位

b a r f o o t h e f o o b a r

L

R

之后循环上述操作即可

有细心的小伙伴会发现,上面的流程没有讨论完所有的子串,我们还需要以如下的两种情况,继续上述的操作,也就是在上述的循环操作要执行 size 次

b a r f o o t h e f o o b a r

L

R

b a r f o o t h e f o o b a r

L

R

相关推荐
lamentropetion7 分钟前
E - Equal Tree Sums CF1656E
算法
代码游侠9 分钟前
应用——智能配电箱监控系统
linux·服务器·数据库·笔记·算法·sqlite
2301_8008951011 分钟前
hh的蓝桥杯每日一题--前缀和
职场和发展·蓝桥杯
Xの哲學24 分钟前
Linux Platform驱动深度剖析: 从设计思想到实战解析
linux·服务器·网络·算法·边缘计算
逑之31 分钟前
C语言笔记11:字符函数和字符串函数
c语言·笔记·算法
栈与堆44 分钟前
LeetCode-1-两数之和
java·数据结构·后端·python·算法·leetcode·rust
不知名XL1 小时前
day20 回溯算法part02
算法
嵌入式进阶行者1 小时前
【算法】TLV格式解析实例:华为OD机考双机位A卷 - TLV解析 Ⅱ
数据结构·c++·算法
OC溥哥9991 小时前
Paper MinecraftV3.0重大更新(下界更新)我的世界C++2D版本隆重推出,拷贝即玩!
java·c++·算法
Jayden_Ruan1 小时前
C++蛇形方阵
开发语言·c++·算法