【C++】滑动窗口算法习题


🎆个人主页:夜晚中的人海

今日语录:人生就是这样,要耐的住寂寞,才守得住繁华

文章目录

🚀一、长度最小的子数组

题目链接:长度最小的子数组

题目描述:

解题思路:

1.暴力枚举,枚举任意一个数字当作起始位置,然后从这个位置开始寻找一段最短区间满足 >= target(注:这方法会超时,效率低)

2.滑动窗口 ,由于题目要的是一段连续的区间,因此我们可以采用滑动窗口的办法。使用两个指针left和right同时指向起始位置,在right小于数组长度前提下,不断向右移动进行累加操作(进窗口 )直到它 >= target(判断条件 ),记录该段区间的长度(更新结果 ),然后将左端元素划出去(出窗口)同时并判断是否满足条件,如果不满足,则让right++ (进入下一个窗口)

代码实现:

cpp 复制代码
class Solution {
public:
    int minSubArrayLen(int target, vector<int>& nums) {
        int ret = INT_MAX,sum = 0;
        for(int left = 0,right = 0;right < nums.size();right++)
        {
            sum += nums[right];
            while(sum >= target)
            {
                //更新结果
                ret = min(ret,right - left + 1);
                sum -= nums[left++];
            }
        }
        return ret == INT_MAX ? 0 : ret;
    }
};

🎉二、无重复字符的最长子串

题目链接:无重复字符的最长子串

题目描述:

解题思路:

1.暴力枚举,从每一个位置开始向后,看看无重复字符在什么位置,返回长度最长的那个(注:效率低)

2.滑动窗口 + 哈希表 ,题目要求依旧是一段连续的区间,因此可以采用滑动窗口的办法。定义两个指针left 和 right,让右端元素right进入窗口(进窗口 ),并用哈希表统计该字符的频次,如果该字符 > 1(判断条件 ),则从左侧开始滑出窗口(出窗口 ),直到该字符的频次为1时,更新结果

代码实现:

cpp 复制代码
class Solution {
public:
    int lengthOfLongestSubstring(string s) {
        int hash[128] = {0};
        int n = s.size();
        int ret = 0;  
        for(int left = 0,right = 0;right < n;right++)
        {
            hash[s[right]]++;
            while(hash[s[right]] > 1)
            {
                hash[s[left++]]--;
            }
            ret = max(ret,right - left + 1);
        }
        return ret;
    }
};

🚘三、最大连续1的个数 III

题目链接:最大连续1的个数 III

题目描述:

解题思路:

1.因为该题的要求依旧是一段连续的空间,因此我们可以采用滑动窗口的方法来解决。

2.我们不要想着如何去翻转,把问题复杂化。它的核心就是0的个数不超过k个,我们只要解决这一问题即可

3.可以使用一个变量zero来记录0的个数,用两个指针left和right,right指针负责进窗口 ,当遇到0时让zero++,直到当zero > k时(判断条件 ),判断left所指元素是否为0进行出窗口 ,最后更新结果

代码实现:

cpp 复制代码
class Solution {
public:
    int longestOnes(vector<int>& nums, int k) {
        int n = nums.size();
        int len = 0;
        for(int left = 0,right= 0,zero = 0;right < n;right++)
        {
            if(nums[right] == 0)
            {
                zero++;
            }
            while(zero > k)
            {
                if(nums[left++] == 0)
                {
                    zero--;
                }
            }
            len = max(len,right - left + 1);
        }
        return len;
    }
};

🎡四、将x减到0的最小操作数

题目链接:将x减到0的最小操作数

题目描述:

解题思路:

由于题目要求的是减去数组左或右两端连续的和为x的最短数组,如果按照题目的要求那我们解决这个问题就比较棘手,由于我们不知道它是减去左边的还是减去右边的,或者连续减去左边等情况,因此我们可以将其进行转化为数组内一段连续的和为sum(nums) - x的最长数组,使用滑动窗口的解法,然后用整个数组的大小减去该段最长数组的大小,我们就得到了题目要求的最短操作数了

代码实现:

cpp 复制代码
class Solution {
public:
    int minOperations(vector<int>& nums, int x) {
        int sum = 0;
        for(auto n : nums)
        {
            sum += n;
        }
        int ret = -1;
        int target = sum - x;
        if(target < 0)
        {
            return -1;
        }
        for(int left = 0,right = 0,tmp = 0;right < nums.size();right++)
        {
            tmp += nums[right];
            while(tmp > target)
            {
                tmp -= nums[left++];
            }
            if(tmp == target)
            {
                ret = max(ret,right - left + 1);
            }
        }
        if(ret == -1)
            return ret;
        else
            return nums.size() - ret;
    }
};

🏝️五、找到字符中所有字母的异位词

题目链接:找到字符中所有字母的异位词

题目描述:

解题思路:
滑动窗口+ 哈希表 ,由题可知,字符串p的异位词的长度⼀定与字符串p的长度相同,所以可以在字符串s 中构造⼀个长度为字符串p的长度相同的滑动窗口,用哈希表记录字符串p中字符出现的个数,用一个变量count记录长度,不断进窗口 ,如果大于异位词的长度并且出现的字符在字符串p中也有(判断条件 ),就出窗口 ,让count--,相反就让count++,如果等于字符串p的长度就更新结果

代码实现:

cpp 复制代码
class Solution {
public:
    vector<int> findAnagrams(string s, string p) {
        vector<int> ret;
        int hash1[26] = {0};
        int n = s.size();
        int m = p.size();
        for(auto ch : p)
        {
            hash1[ch - 'a']++;
        }
        int hash2[26] = {0};
        int count = 0;
        for(int left = 0,right = 0;right < n;right++)
        {
            char in = s[right];
            if(++hash2[in - 'a'] <= hash1[in - 'a'])
            {
                count++;
            }
            if(right - left + 1 > m)
            {   char out = s[left++];
                if(hash2[out - 'a']-- <= hash1[out - 'a'])
                {
                    count--;
                }
            }
            if(count == m)
            {
                ret.push_back(left);
            }
        }
        return ret; 
    }
};

⭐六、串联所有单词的子串

题目链接:串联所有单词的子串

题目描述:

解题思路:

这道题的解法与上道题的异位词解法类似,无非就是把字母转化为一个单词,因此同样采用哈希 + 滑动窗口的解法

代码实现:

cpp 复制代码
class Solution {
public:
    vector<int> findSubstring(string s, vector<string>& words) {
        vector<int> ret;
        unordered_map<string ,int> hash1;
        for(auto& e:words)
        {
            hash1[e]++;
        }
        int len = words[0].size();
        int m = words.size();
        for(int i = 0;i < len;i++)
        {
            unordered_map<string,int> hash2;
            for(int left = i,right = i,count = 0;right + len <= s.size();right += len)
            {
                string in = s.substr(right,len);
                hash2[in]++;
                if(hash2[in] <= hash1[in])
                {
                    count++;
                }
                if(right - left + 1 > len * m)
                {
                    string out = s.substr(left,len);
                    if(hash2[out] <= hash1[out])
                    {
                        count--;
                    }
                    hash2[out]--;
                    left += len;
                }
                if(count == m)
                {
                    ret.push_back(left);
                }
            }
        }
        return ret;
相关推荐
~无忧花开~2 小时前
CSS学习笔记(五):CSS媒体查询入门指南
开发语言·前端·css·学习·媒体
kesteler3 小时前
R-切割数据
开发语言·r语言
哞哞不熬夜3 小时前
JavaEE--SpringIoC
java·开发语言·spring boot·spring·java-ee·maven
newxtc3 小时前
【猿辅导-注册安全分析报告-无验证方式导致安全隐患】
开发语言·selenium·安全·yolo·安全爆破
张人玉3 小时前
c#WPF基础知识
开发语言·c#·wpf
AA陈超3 小时前
虚幻引擎5 GAS开发俯视角RPG游戏 P06-09 玩家等级与战斗接口
c++·游戏·ue5·游戏引擎·虚幻
violet-lz3 小时前
数据结构四大简单排序算法详解:直接插入排序、选择排序、基数排序和冒泡排序
数据结构·算法·排序算法
·白小白3 小时前
力扣(LeetCode) ——118.杨辉三角(C++)
c++·算法·leetcode
tongsound3 小时前
libmodbus 使用示例
linux·c++