串联所有单词的子串

目录

一:题目链接

二:题目思路

三:代码实现


一:题目链接

二:题目思路

          这道题和我们讲过的 “ 找到字符串中所有字母异位词-优快云博客 ” 思路很类似,只不过只是在此基础上把 字母 换成了 字符串。请务必理解上述链接的博客,再看这道题的思路。

        理解上述博客后,再把题目想象成这样子:

        也就是类似于把 字符串 换成了 字母,再判断是不是互为 “ 异位词 ”

        所以,我们可以利用滑动窗口,首先定义一个 left 和 right 指针在字符串 s 的起始位置,再定义一个 count 变量来记录有效元素个数。之后的每次移动,left 和 right 都是移动字符串数组 words 中每个元素字符串的长度。

        进窗口期间使用哈希表记录 right 每个位置获得对应子串个数。比如“aaa”,“bbb”,(后面的代码有写获取的方法,即 substring ),如果是有效元素,则 count ++。

         期间的控制判断条件是 left 和 right 之间(包含 left 和 right)含有的长度是否大于字符串数组 words  的 字符串元素个数 * 每个字符串元素的长度

        更新结果利用有效元素个数是否等于字符串数组元素个数来判断当前 left 下标是否符合题目要求。

        到这里还没结束,看下图:

        上述我们只是滑动了一次窗口,还没有枚举上图中绿线和蓝线的情况。所以,我们要以 符串数组 words 中字符串元素的大小作为 “滑动窗口” 次数。期间会涉及到容器的使用,可以很好锻炼使用容器的能力。

三:代码实现

        //存储下标结果
        List<Integer> ret = new ArrayList<Integer>();

        //得到 world 字符串数组不同单词的个数
        Map<String,Integer> hash2 = new  HashMap<String,Integer>();
        for(String str : words) {
            hash2.put(str,hash2.getOrDefault(str,0) + 1);
        }

        // words 字符串数组每个单词的长度和数组元素个
        int len = words[0].length();
        int k = words.length;

        //字符串 s 的长度
        int m = s.length();

        //需要 len 次滑动窗口
        for(int i = 0;i < len;i++) { 

            //一次滑动窗口
            int left = i;
            Map<String,Integer> hash1 = new HashMap<String,Integer>();

            //记录有效元素的个数
            int count = 0;

            for(int right = i;right + len <= m;right += len) {

                //进窗口
                String come = s.substring(right,right + len);
                hash1.put(come,hash1.getOrDefault(come,0) + 1);

                //判断是否有效元素
                if(hash1.get(come) <= hash2.getOrDefault(come,0)) {
                    count++;
                }

                //判断
                if(right - left + 1 > len * k) {
                    //出窗口前,判断要出的元素是不是有效元素
                    String out = s.substring(left,left + len);
                    if(hash1.get(out) <= hash2.getOrDefault(out,0)) {
                        count--;
                    }
                    hash1.put(out,hash1.get(out) - 1);
                    left += len;
                }
                //更新结果
                if(count == k) {
                    ret.add(left);
                }
            }
        }
        return ret;

        上面滑动窗口的循环 right 的边界处理使用了 right + len <= m 来判断,可以很好预防 right 走到后面临界时的越界情况。

        String come = s.substring(right,right + len);这条代码的作用是从字符串 s 中截取一段子字符串,并将其赋值给变量come。

        hash1.put(come,hash1.getOrDefault(come,0) + 1) ; 里面的 hash1.getOrDefault(come,0)  是先查看 hash1 这个 Map 中有没有 come 这个键,如果有,就返回他当前的个数,如果没有,就返回为 0 。然后整段代码表示将 come 这个键 加一。(如果没有 come 这个键 ,Map 的put 方法有创建键的过程)。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值