LeetCode30 串联所有单词的子串

原题目

在这里插入图片描述

代码分析
方法一:暴力法

图片来源点击此处
i从0开始遍历,在所有单词总长范围内,判断是否符合要求,符合要求添加当前i下标
i移向下一个,继续判断
要找到满足所有words数组单词的子串
1.先统计words每个单词的个数
2.从i开始遍历,截取单个单词长度的字符串,如果该字符串比 words的该单词个数小,则i移向下一个单词的首地址,否则停止,如果能遍历到words所有单词总长度结尾,即符合条件
在这里插入图片描述

class Solution {
public:
    vector<int> findSubstring(string s, vector<string>& words) {
        if(words.size()==0)return {};

        vector<int>res;
        unordered_map<string ,int>m1,m2;
        for(auto word :words){//统计words各个单词个数
            m1[word]++;
        }

        int len = words.size()*words[0].size(); //words所有单词总长度
        for(int i = 0; i+len <= s.size(); i++){//从0开始遍历
            int j = i;
            for(; j < i+len; j+=words[0].size()){//每次判断长度为len的字符串是否包含所有的words
                string temp = s.substr(j,words[0].size());//截取单个单词
                if(m2[temp]>=m1[temp]){//如果比words的该单词多,说明不符,停止
                    break;
                }
                m2[temp]++;//统计s各个截取单词数
            }
            if(j == i+len){//如果遍历到最后,符合要求
                res.push_back(i);
            }
            m2.clear();//清空s中统计的单词,方便下一次重新开始统计
        }
        return res;
    }
};
方法二: 双指针+滑动窗口

因为words的单个单词等长,设单词长度为n,所以可以分为n类情况
对每种情况进行相同操作:
1.左右指针均从当前情况的下标i开始
2.如果右指针的当前截取单词不在words中,说明当前范围不符合条件,直接将左右指针移向下一个单词,重新统计截取的单词
3.如果右指针当前所截取的单词比words的还多,说明当前范围不符合条件,缩减左边界,并去掉统计过的单词,直到右指针当前所截取的单词比words少
4.如果右指针当前所截取的单词比words少,扩展右边界,直到满足words所有单词为止,即 右指针和左指针的区间长度为words所有单词总长度,符合条件,左指针为一个答案
5.以上滑动窗口执行n次
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

class Solution {
public:
    vector<int> findSubstring(string s, vector<string>& words) {
        if(words.size()==0)return {};

        vector<int>res;
        unordered_map<string ,int>m1,m2;//m1统计words各个单词数,m2统计截取的各个单词数
        for(auto word :words){
            m1[word]++;
        }

        int len = words.size()*words[0].size();
        int word_size = words[0].size(); 
        for(int i = 0; i < word_size&&i+len <= s.size(); i++){//1~word_size种情况
            int j = i, k = i;
            while(k<s.size()){
                string temp = s.substr(k,word_size);
                if(m1[temp] == 0){//如果words不存在该单词,直接从下一个开始重写统计
                    k+=word_size;
                    j = k;
                    m2.clear();
                }else if(m2[temp]<m1[temp]){//如果比words该单词少,继续扩展右边界
                    m2[temp]++;
                    k+=word_size;
                }else{//如果比words该单词多,缩减左边界,直至比words该单词少
                    m2[s.substr(j,word_size)]--;
                    j+=word_size;
                }
                if(k-j==len){//如果找到words所有单词,添加左指针
                    res.push_back(j);
                }
            }
            m2.clear();
        }
        return res;
    }
};
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Baal Austin

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值