[LC优选算法#4] 滑动窗口 | 串联所有单词的⼦串 | 最⼩覆盖⼦串

滑动窗口专题:

LC优选算法#2 滑动窗口 | 长度最小的子数组 | 无重复字符的最长子串 | 最大连续1的个数

LC优选算法#3 滑动窗口 | 将x减到0的最⼩操作数 | ⽔果成篮 | 字⺟异位词

1. 串联所有单词的⼦串

串联所有单词的⼦串

解题思路:滑动窗口 O(len * N)

研究对象是连续区间,可以尝试用滑动窗口的思想解决。

题目中限定了每个字符串的长度相同,如果把一个个字符串当作字母来处理,就可以转化为「字符串中所有的字⺟异位词」(Leetcode438)。

如果words数组中有n个单词,每个单词长度为len

  • 首先需要用一个哈希表 hash1 存储words数组中字符串的种类和个数,另外一个哈希表 hash2 用于存储滑动窗口中截取子串内部单词的种类和个数。
  • 窗口内部,用双指针划分窗口内的每个长度为 len 的单词,放入 hash2 中,再用count 来统计窗口中的有效单词。最后通过比对 countn 是否相同来更新结果。

那么滑动窗口的起点应该怎么确定呢?通过观察发现,单词的长度 len 是固定统一的,那么仅需从第一个单词的每一位 向后使用一次滑动窗口,就可以把所有情况都包括在内了:

整体思路如下:

由于总共需要遍历len次数组,因此时间复杂度为O(len * N)

cpp 复制代码
class Solution {
public:
    vector<int> findSubstring(string s, vector<string>& words)
    {
        unordered_map<string, int> hash1; //样板
        vector<int> ret;

        for(auto& str : words)
        {
            hash1[str]++;
        }

        int n = words.size(); //字符串个数
        int len = words[0].size(); //字符串单位长度

        for(int i=0; i<len; i++)
        {
            unordered_map<string, int> hash2;
            int count = 0;
            for(int left=i, right=i; right+len<=s.size(); right+=len)
            {
                //进窗口+维护count
                string in = s.substr(right, len);
                hash2[in]++;
                if(hash1.count(in) && hash2[in] <= hash1[in])
                {
                    count++;
                }

                //判断
                if(right - left + 1 > len * n)
                {
                    //出窗口+维护count
                    string out = s.substr(left, len);
                    //单词存在且单词个数未满 == 有效单词
                    if(hash1.count(out) && hash2[out] <= hash1[out])
                    {
                        count--;
                    }

                    hash2[out]--;
                    left += len;
                }

                //更新结果
                if(count == n)
                {
                    ret.push_back(left);
                }
            }
        }

        return ret;
    }
};

2. 最⼩覆盖⼦串

最⼩覆盖⼦串

解题思路:滑动窗口 O(N)

研究对象是连续区间,可以尝试用滑动窗口的思想解决。

  • 使用一个哈希表hash1统计目标子串中的字符的个数,kinds变量统计hash1中字符的种类。
  • 窗口内部,一个哈希表hash2统计当前窗口中的字符个数。count变量统计hash2中有效字符的种类。最后通过比对countkinds来更新结果。

一些细节 :由于题目所求的是最小子串,因此可以用substr库函数截取最小子串,这其中需要提供子串的起始下标begin和长度len作为参数,因此需要在更新结果时记录。

两个指针在最坏情况下近似于分别遍历一次子串,相当于N*N,因此时间复杂度为O(N)

cpp 复制代码
class Solution {
public:
    string minWindow(string s, string t)
    {
        int hash1[128] = {0};
        int kinds = 0;
        for(auto ch : t)
        {
            if(hash1[ch] == 0)
            {
                kinds++;
            }
            hash1[ch]++;
        }

        int begin = -1;
        int len = INT_MAX;

        int hash2[128] = {0};
        for(int left=0, right=0, count=0; right < s.size(); right++)
        {
            //进窗口
            char in = s[right];
            hash2[in]++;
            if(hash2[in] == hash1[in])
            {
                count++;
            }

            //判断
            while(count == kinds)
            {                
                //更新结果
                if(right - left + 1 < len)
                {
                    begin = left;
                    len = right - left + 1;
                }
                
                //出窗口
                char out = s[left];
                if(hash2[out] == hash1[out])
                {
                    count--;
                }
                
                hash2[out]--;
                left++;
            }
        }
       
        if(begin == -1) return "";
        return s.substr(begin, len);
    }
};

// 本期内容就到这里啦,如果对你有帮助,请三连支持!我是青云,我们下期见^_~

相关推荐
203号居民1 小时前
LeetCode hot 100 — 141. 环形链表2
算法·leetcode·链表
玖玥拾2 小时前
LeetCode 202 快乐数
算法·leetcode
LuminousCPP2 小时前
数据结构-二叉树(六):BFS层序遍历与完全二叉树判断|复用链式队列 + (N_0=N_2+1) 性质证明
c语言·数据结构·笔记·算法·二叉树·宽度优先
ZhouDevin3 小时前
算法论文/数据集3——CLD(TMLR2025)压缩训练集,仅保留对验证集有益的样本
人工智能·深度学习·算法·计算机视觉
码匠许师傅3 小时前
【设计模式精讲】14.外观模式(Facade)
c++·设计模式·uml·外观模式
Tim_103 小时前
【LeetCode】29、两数相除
算法·leetcode·职场和发展
船厂电气自动化ai大模型4 小时前
AI大模型与数学/第63课:矩阵定义、矩阵加法、标量乘法(逐级精讲)
数据结构·人工智能·深度学习·线性代数·算法
余额瞒着我当琳4 小时前
算法修炼 chapter 2 双指针进阶、盛最多水的容器、有效三角形的个数、两数之和、三数之和、四数之和
算法
你压到我腿毛了6664 小时前
C语言冒泡算法(Bubble sort)
c语言·数据结构·算法
xxwxx__5 小时前
C++ list 深度解析:从使用原理到模拟实现
开发语言·c++·list