leetcode滑动窗口算法

  1. 尽可能使字符串相等
给你两个长度相同的字符串,s 和 t。

将 s 中的第 i 个字符变到 t 中的第 i 个字符需要 |s[i] - t[i]| 的开销(开销可能为 0),也就是两个字符的 ASCII 码值的差的绝对值。

用于变更字符串的最大预算是 maxCost。在转化字符串时,总开销应当小于等于该预算,这也意味着字符串的转化可能是不完全的。

如果你可以将 s 的子字符串转化为它在 t 中对应的子字符串,则返回可以转化的最大长度。

如果 s 中没有子字符串可以转化成 t 中对应的子字符串,则返回 0。
class Solution {
public:
    int equalSubstring(string s, string t, int maxCost) {
        int res = 0;
        int right = 0;
        int left = 0;
        int len = s.size();
        int sum = 0;
        while(right < len){
            sum += (s[right] > t[right])?(s[right] - t[right]):(t[right] - s[right]);
            while(sum > maxCost){
                sum -= (s[left] > t[left])?(s[left] - t[left]):(t[left] - s[left]);
                left++;
            }
            right++;
            res = (res > (right - left))?res:(right - left);
        }
        return res;
    }
};
  1. 定长子串中元音的最大数目
给你字符串 s 和整数 k 。

请返回字符串 s 中长度为 k 的单个子字符串中可能包含的最大元音字母数。

英文中的 元音字母 为(a, e, i, o, u)。
class Solution {
public:
    int maxVowels(string s, int k) {
            int right = 0;
            int left = 0;
            int sum = 0;
            int max = 0;
            int len = s.length();
            while(right < len){
                sum += isYuan(s[right]);
                right++;
                if(right - left == k){
                    max = (max > sum)?max:sum;
                    sum -= isYuan(s[left]);
                    left++;
                }
            }
            return max;
    }
    int isYuan(char c){
        return (c == 'a'||c == 'e'||c == 'i'||c == 'o'||c == 'u')?1:0;
    }
};
  1. 滑动窗口最大值
if(k == 0)return {};
    vector<int> res;
    deque<int> Q;
    for(int i = 0;i < k;++i){
        while(!Q.empty()&&nums[i] > nums[Q.back()]){
            Q.pop_back();
        }
        Q.push_back(i);
    }
    res.push_back(nums[Q.front()]);

    for(int i = k;i < nums.size();++i){
        if(!Q.empty() && Q.front() <= i - k){
            Q.pop_front();
        }
        while(!Q.empty() && nums[i] > nums[Q.back()] ){
            Q.pop_back();
        }
        Q.push_back(i);
        res.push_back(nums[Q.front()]);
    }
    return res;
}

这里有一个问题要请教各位大佬,就是在
while(!Q.empty() && nums[i] > nums[Q.back()] )和
while(!Q.empty()&&nums[i] > nums[Q.back()])中如果将!Q.empty()的位置放到后面也就是while(nums[i] > nums[Q.back()] && !Q.empty())的形式会报错,memory cannot be printed,求问是为什么?


问题查明了,自己犯2了,出错原因在于当Q为空的时候,要先判断Q.empty(),这样后面的条件才不会去判断,不然的话由于后面条件用到了Q.back(),当Q为空时就会发生访问错误
所以细致很重要,以此为戒

  1. 绝对差不超过限制的最长连续子数组
class Solution {
public:
    int longestSubarray(vector<int>& nums, int limit) {
        deque<int> max_queue,min_queue;
        int left = 0,right = 0,res = 0;
        while(right < nums.size()){
            //这两步保证了max_queue和min中的头部都是滑动窗口中最大和最小的值
            //因为使用set与multiset时,机器内部使用平衡二叉树用于保证容器中数据的有序,
            //插入与删除的操作是logn,比较滑动窗口内部最大值与最小值的差值时需要这些操作
            //因此使用双端队列可以O(1)
            while(!max_queue.empty() && max_queue.back() < nums[right]){
                max_queue.pop_back();
            }
            while(!min_queue.empty() && min_queue.back() > nums[right]){
                min_queue.pop_back();
            }
            max_queue.push_back(nums[right]);
            min_queue.push_back(nums[right]);
            //假设8,4,2,此时max里的就是8,4,2,min里的是2,left++时符合
            //2,4,8,此时max里的就是8,min里的是2,4,8,符合
            //4,2,8,max:8,min:2,8,left++后两个deque中仍然是滑动窗口里的值
            //以上情况说明了删除以下删除操作可以保证了max和min队列中的数据是滑动窗口内的数据
            while(max_queue.front() - min_queue.front() > limit){
                if(max_queue.front() == nums[left]){
                    max_queue.pop_front();
                }
                if(min_queue.front() == nums[left]){
                    min_queue.pop_front();
                }
                left++;
            }
            res = max(res,right - left + 1);
            right++;
        }
        return res;
    }
};

//使用multiset的版本,multiset与set不同的地方在于set会去除重复的值
class Solution {
public:
    int longestSubarray(vector<int>& nums, int limit) {
        multiset<int> box;
        int left = 0,right = 0;
        int res = 0;
        while(right < nums.size()){
            box.insert(nums[right]);
            while(*box.rbegin() - *box.begin() > limit){
                box.erase(box.find(nums[left]));
                left++;
            }
            res = max(res,right - left + 1);
            right++;
        }
        return res;
    }
};

  1. 最大连续1的个数 III

class Solution {
public:
    int longestOnes(vector<int>& A, int K) {
        int right = 0,left = 0;
        int res = 0;
        int one_num = 0,zero_num = 0;
        while(right < A.size()){
            if(A[right] == 1){
                one_num++;
            }
            else zero_num++;
            while(zero_num > K){
                if(A[left] == 1){
                    one_num--;
                }
                else zero_num--;
                left++;
            }
            res = max(res,one_num + zero_num);
            right++;
        }
        return res;
    }
};

https://www.cnblogs.com/huansky/p/13488234.html
https://blog.csdn.net/Dby_freedom/article/details/89066140
https://leetcode-cn.com/problems/sliding-window-maximum/solution/zhe-hui-yi-miao-dong-bu-liao-liao-de-hua-7fy5/
https://leetcode-cn.com/problems/sliding-window-maximum/solution/shuang-xiang-dui-lie-jie-jue-hua-dong-chuang-kou-z/

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值