leetcode_30.串联所有单词的子串

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

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

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

示例 2:
输入:
s = “wordgoodgoodgoodbestword”,
words = [“word”,“good”,“best”,“word”]
输出:[]

解析:对于字符串的相关问题,许多时候可以用滑动窗口的方式解决,即先扩大范围即右边界,直到不符合要求时,再推进左边界缩小范围。
具体解析见代码

class Solution {
public:
    vector<int> findSubstring(string s, vector<string>& words) {
        unordered_map<string,int> word_map;
        vector<int> res;
        if(words.size()==0) return res;
        int word_len = words[0].size();
        int word_num = words.size();
        if(s.size()<word_num*word_len) return res;
        //构造目标map
        for(string str:words) word_map[str]++;
        //遍历字符串word_len次即可覆盖所有可能情况
        for(int i=0;i<word_len;++i){
            //子串的左右边界
            int left = i;
            int right = i;
            //子串查找map
            unordered_map<string, int> find_map;
            //成功匹配的个数
            int count = 0;
            //如果右边界能够继续扩展,则扩展右边界
            //此处右边界在最后匹配位置的右侧,因此是小于等于。
            while(right+word_len<=s.size()){
                //获取待匹配的子串
                string cur = s.substr(right, word_len);
                //匹配个数加一
                ++count;
                //右边界继续推进
                right += word_len;
                //如果该子串不存于目标map中,即该单词不存在与words中
                //代表包括该子串在内的目前边界,必然无法与words匹配,
                //因此放弃已经匹配的结果,将左边界推进至等于右边界
                if(word_map[cur]==0){
                    count=0;
                    left=right;
                    find_map.clear();
                    continue;
                }
                //否则该单词存在于words中,对应查找map值加一
                find_map[cur]++;
                //此时可能存在一种情况,即该单词出现次数过多,超过了words中的数量
                //则将左边界向右推进,将因推进而离开子串边界的单词从查找map中去除
                //直至该单词的数量符合要求,注意推进会减少已经匹配单词的数量。
                while(find_map[cur]>word_map[cur]){
                    string lefts = s.substr(left, word_len);
                    left += word_len;
                    find_map[lefts]--;
                    count--;
                }
                //处理后,如果匹配单词的数量达到了words_len
                //即目前的子串与words完全匹配,将其左边界即子串起始位置索引返回
                if(count==word_num) res.push_back(left);
            }
        }
        return res;
    }
};
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值