106.串联所有单词的字串

一、题目描述

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

注意子串要与 words 中的单词完全匹配,中间不能有其他字符 ,但不需要考虑 words 中单词串联的顺序。
在这里插入图片描述
在这里插入图片描述

二、解题思路

方案一:使用哈希查找,具体看代码。

方案二:滑动窗口

以示例一为例,因为words中的单词长度是3,所以每3个字母是一组
在这里插入图片描述
第一步:前三个是一组,然后和words中的单词比较,发现bar出现了一次,然后right继续向后找,发现foo也出现了一次,这时words中的每个单词都出现了,且次数也符合,更新当前结果集res=0
在这里插入图片描述
在这里插入图片描述
第二步:right继续向后遍历,这时the并不是words中的单词,就要缩小窗口,left向后移动到the后面重新开始:
在这里插入图片描述
重复第一第二步,当满足words中的单词和其次数都在窗口中出现时,则更新res

三、代码演示

class Solution {
    public List<Integer> findSubstring(String s, String[] words) {
        //声明一个结果集
        Map<String, Integer> map = new HashMap<>();

        //统计word中每个单词出现的次数
        for (String word : words){
            //getOrDefault表示当前有word值就获取key对应的value,没有返回默认值0
            map.put(word, map.getOrDefault(word, 0)+1);
        }

        //一个单词的长度,题目说了words中单词长度相同
        int oneWordLen = words[0].length();
        //单词个数
        int wordNum = words.length;
        //所有单词总长度
        int totalLen = oneWordLen * wordNum;

        List<Integer> res = new ArrayList<>();
        for (int i=0; i<s.length()-totalLen+1; i++){
            //拿到等于所有单词长度之和的字串
            String subStr = s.substring(i, i+totalLen);
            //统计子串中单词出现的次数
            Map<String, Integer> tmpMap = new HashMap<>();
            for (int j=0; j<totalLen; j+=oneWordLen){
                String oneWord = subStr.substring(j, j+oneWordLen);
                tmpMap.put(oneWord, tmpMap.getOrDefault(oneWord, 0)+1);
            }

            //如果单词出现的次数和原始words中单词出现的此时相同,则符合条件
            if (map.equals(tmpMap)){
                res.add(i);
            }
        }
         return res;
    }
}

时间复杂度:O(n^2)

滑动窗口代码:

class Solution {
    public List<Integer> findSubstring(String s, String[] words) {
        //声明一个结果集
        Map<String, Integer> map = new HashMap<>();

        //统计word中每个单词出现的次数
        for (String word : words){
            //getOrDefault表示当前有word值就获取key对应的value,没有返回默认值0
            map.put(word, map.getOrDefault(word, 0)+1);
        }

        //一个单词的长度,题目说了words中单词长度相同
        int oneWordLen = words[0].length();
        //单词个数
        int wordNum = words.length;
        //所有单词总长度
        int totalLen = oneWordLen * wordNum;
        //声明一个结果集
        List<Integer> res = new ArrayList<>();
        for (int i=0; i<oneWordLen; i++){
            //声明一个指针
            int left=i, right=i;
            //使用一个变量来存储匹配单词的个数
            int matchedWords = 0;
            Map<String, Integer> windowMap = new HashMap<>();
            while (right<=s.length()-oneWordLen){
                //获取到当前单词
                String currWord = s.substring(right, right+oneWordLen);
                //将当前单词加到窗口里面
                windowMap.put(currWord, windowMap.getOrDefault(currWord,0)+1);
                matchedWords++;
                //如果当前窗口里面单词出现的次数大于words里面单词出现的次数,则缩减窗口
                while (windowMap.getOrDefault(currWord,0)>map.getOrDefault(currWord,0)){
                    String leftWord = s.substring(left,left+oneWordLen);
                    windowMap.put(leftWord, windowMap.getOrDefault(leftWord,0)-1);
                    left += oneWordLen;
                    matchedWords--;
                }
                if (matchedWords == wordNum){
                    res.add(left);
                }
                right += oneWordLen;
            }
        }
        return res;
    }
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值