滑动窗口(二)

文章目录

  • Leetcode1658. 将 x 减到 0 的最小操作数
    • 题目
    • 解法(滑动窗口)
  • Leetcode904. 水果成篮
    • 题目
    • 解法(滑动窗口)
  • Leetcode438. 找到字符串中所有字母异位词
    • 题目
    • 解法(滑动窗口)

Leetcode1658. 将 x 减到 0 的最小操作数

题目

Leetcode1658. 将 x 减到 0 的最小操作数

解法(滑动窗口)

题目的意思就是左边或者右边减掉一个数,使减掉的数的和恰好为 x ,我们其实并不能很清楚的知道应该从哪边开始减,这样问题就变得复杂起来。因此,我们对题目进行一个转化,等价为求数组内一段连续的、最长的和为sum(nums) - x的数组

  • 首先转换问题,int target = sum(nums) - x 。特判一下如果target < 0,则无解,这也就意味着我把你数组内的所有元素都减完,我x仍然大于0;
  • 初始化左右指针int left = 0, right = 0
  • right < nums.size()时,一直循环;
    进窗口
    if(t > target), 出窗口

代码

class Solution 
{
public:
    int minOperations(vector<int>& nums, int x) 
    {
        int sum = 0;
        for(auto e:nums) sum += e;//求整个数组的和

        int res = -1;
        int target = sum - x; //转换问题
        if(target < 0) return -1;//特判

        for(int left = 0, right = 0, t = 0; right < nums.size(); right++)
        {
            t += nums[right];//进窗口
            while(t > target)//判断 
                t -= nums[left++];//出窗口
            
            if(t == target) res = max(res, right - left + 1);//更新结构
        }
        return res == -1 ? -1 : nums.size() - res;
    }
};

Leetcode904. 水果成篮

题目

Leetcode904. 水果成篮

解法(滑动窗口)

使窗口内的水果种类只有两种
右端⽔果进⼊窗⼝的时候,⽤哈希表统计这个⽔果出现的次数。这个⽔果进来后,判断哈希表的大小:
如果大于2,说明窗口中水果种类超过两种。那么左侧窗口就依次出水果并更新哈希表内水果种类,直至哈希表大小等于2,那么更新结果;
如果小于等于2,那么直接更新结果;

//使用容器
class Solution 
{
public:
    int totalFruit(vector<int>& fruits) 
    {
        unordered_map<int, int> hash; // 统计窗⼝水果的种类

        int res = 0;
        for(int left = 0, right = 0; right < fruits.size(); right++)
        {
            int in = fruits[right];
            hash[in]++;//进窗口
            while(hash.size() > 2)//判断
            {
                int out = fruits[left];
                hash[out]--;//出窗口

                //当左侧水果种类个数为零的时候,从hash中剔除
                if(hash[out] == 0) hash.erase(out);

                left++;
            }
            res = max(res, right - left + 1);
        }
        return res;
    }
};

滑动窗口(二)_第1张图片

但是使用容器的话,需要不停地在hash中插入数据,这样消耗其实是非常大的,下面我们使用数组模拟hash,这样消耗就会小一点,

//⽤数组模拟哈希表
class Solution 
{
public:
    int totalFruit(vector<int>& fruits) 
    {
        int hash[100001] = {0};//数组模拟哈希表

        int res = 0;
        int kinds = 0;//记录水果的种类
        for(int left = 0, right = 0; right < fruits.size(); right++)
        {
            int in = fruits[right];
            if(hash[in]++ == 0) kinds++;//维护kinds水果种类以及进窗口

            while(kinds > 2)//判断
            {
                int out = fruits[left];
                if(--hash[out] == 0) kinds--;//维护kinds水果种类以及出窗口
                left++;
            }
            res = max(res, right - left + 1);//更新结果
        }
        return res;
    }
};

在这里插入图片描述

Leetcode438. 找到字符串中所有字母异位词

题目

Leetcode438. 找到字符串中所有字母异位词

解法(滑动窗口)

  • 因为字符串 p 的异位词的⻓度⼀定与字符串 p 的⻓度相同,所以我们可以在字符串 s 中构造⼀个⻓度为与字符串 p 的⻓度相同的滑动窗⼝,维护窗口中没中字母出现的次数;
  • 当窗⼝中每种字⺟的数量与字符串 p 中每种字⺟的数量相同时,则说明当前窗⼝为字符串 p 的异位词;
  • 我们使用两个数组来模拟哈希表,⼀个来保存 s 中的⼦串每个字符出现的个数,另⼀个来保存 p 中每⼀个字符出现的个数。
当我们更新结果时,可以对其进行如下优化
进窗口后,if(hash2[in - 'a'] <= hash1[in - 'a']) count++;
出窗口前,if(hash2[out - 'a'] <= hash1[out - 'a']) count--;
当count == p.size()时,更新结果
class Solution 
{
public:
    vector<int> findAnagrams(string s, string p) 
    {
        int hash1[26] = {0};//统计p中每个字母出现的个数
        for(auto e:p) hash1[e - 'a']++;

        vector<int> res;
        int hash2[26] = {0};//统计窗口中每个字符的个数
        for(int left = 0, right = 0, count = 0; right < s.size(); right++)
        {
            char in = s[right];
            hash2[in - 'a']++;//进窗口
            if(hash2[in - 'a'] <= hash1[in - 'a']) count++;//维护count;

            if(right - left + 1 > p.size())//判断
            {
                char out = s[left++];           
                if(hash2[out - 'a'] <= hash1[out - 'a']) count--;//维护count;
                hash2[out - 'a']--//出窗口
            }
            if(count == p.size()) res.push_back(left);
        }
        return res;
    }
};

你可能感兴趣的:(刷题,算法,哈希,滑动窗口,leetcode)