【LeetCode-30】串联所有单词的子串

问题

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

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

示例

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

解答1:定长滑动窗口+哈希表

class Solution {
public:
    vector<int> findSubstring(string s, vector<string>& words) {
        int n = words.size(), w = words[0].size();
        int end_pos = s.size() - n * w;
        vector<int> res;
        unordered_map<string, int> w_memo;
        for (string& i : words) w_memo[i]++; // 目标哈希表初始化
        for (int i = 0; i <= end_pos; i++) {
            unordered_map<string, int> s_memo;
            for (int j = 0; j < n; j++) {
                string cur = s.substr(i + j * w, w);
                if (!w_memo.count(cur)) break; // 剪枝
                s_memo[cur]++;
            }
            if (s_memo == w_memo) res.push_back(i);
        }
        return res;
    }
};

重点思路

可以先看本题的简化版【LeetCode-567】字符串的排列。本题需要做必要的剪枝。

解答2:变长滑动窗口+哈希表

class Solution {
public:
    vector<int> findSubstring(string s, vector<string>& words) {
        vector<int> res;
        int n = words.size(), w = words[0].size();
        unordered_map<string, int> w_memo;
        for (string& i : words) w_memo[i]++;
        for (int i = 0; i < w; i++) { // 共有w种滑动窗口的情况
            unordered_map<string, int> s_memo;
            int left = i, right = i;
            while (right + w <= s.size()) { // 开始滑动窗口
                string cur = s.substr(right, w);
                right += w;
                if (w_memo.count(cur)) { // 如果要加入的这个存在
                    s_memo[cur]++;
                    while (w_memo[cur] < s_memo[cur]) {
                        s_memo[s.substr(left, w)]--;
                        left += w;
                    }
                    if (right - left == n * w) res.push_back(left); // 长度是否满足要求
                } else { // 否则直接跳过这个
                    left = right;
                    s_memo.clear();
                }
            }
        }
        return res;
    }
};

重点思路

本题如果要使用变长的滑动窗口,首先需要讨论有几种滑动窗口的情况。由于字典中的字符长度都是相同的,我们可以使用类似于【LeetCode-567】字符串的排列这道题的做法,将“单词”当作那道题的“字符”

posted @ 2021-04-16 15:29  tmpUser  阅读(49)  评论(0编辑  收藏  举报