滑动窗口

在这里插入图片描述
问题分析:
题目的内容易于理解,为从一个固定的窗口中找到其中位数,我们要完成的任务是维护一个有序的子序列,如果直接排序的话会超时,可以想到每次其实只是增加了一个元素与删除了一个元素而已
step1 : 找到已经排好序的数组里的要删除的元素进行删除操作
step2:将新插入的元组插入到有序数组中

代码1

class Solution {
public:
    vector<double> medianSlidingWindow(vector<int>& nums, int k) {
        vector<double> res;
        multiset<double> st;
        for (int i = 0; i < nums.size(); ++i) {
            if (st.size() >= k) st.erase(st.find(nums[i - k]));
            st.insert(nums[i]);
            if (i >= k - 1) {
                auto mid = st.begin();
                
                std::advance(mid, k / 2);
                res.push_back((*mid + *prev(mid, (1 - k % 2))) / 2);
            }
        }
        return res;
    }
};

注意:
advance: advance(it, n) it 表示某个迭代器,n 为整数。该函数的功能是将 it 迭代器前进或后退 n 个位置。

prev(it) it 为指定的迭代器,该函数默认可以返回一个指向上一个位置处的迭代器。注意,it 至少为双向迭代器。
my_code

class Solution {
public:
    vector<double> medianSlidingWindow(vector<int>& nums, int k) {
        vector<double> res;
        vector<int> temp(nums.begin(),nums.begin()+k);
        sort(temp.begin(),temp.end());
            if(k%2==0)
            {
                res.push_back(double(long(temp[k/2])+long(temp[(k-1)/2]))/2);
            }
            else
            {
                res.push_back(temp[k/2]);
            }

        for (int i = k; i < nums.size(); ++i) {

            int re = 0;
            for(re = 0;re<temp.size();re++)
            {
                if(temp[re]==nums[i-k])
                {
                    break;
                }
            }
            temp.erase(temp.begin()+re);

            int ins = 0;
            for(ins = 0;ins<temp.size();ins++)
            {
                if(temp[ins]>=nums[i])
                {
                    break;
                }
            }
            temp.insert(temp.begin()+ins,nums[i]);


            if(k%2==0)
            {
                res.push_back(double(long(temp[k/2])+long(temp[(k-1)/2]))/2);
            }
            else
            {
                res.push_back(temp[k/2]);
            }
        }
        return res;
    }
};

滑动窗口双指针同向移动模板:

for(int right;right<n;right++)
{
cnt[s[right]];
while(check(cnt))
{
left++;
}
}
lenght = right - left + 1; //记录与处理

K 个不同整数的子数组

在这里插入图片描述
思路详解: 答案很妙,直接将其恰好转化成了最多,并且用right-left表示了数目,模板还是那个模板,注意right在最后记录之前就++了,所以是一个开区间,最后不用+1
代码:

public class Solution {

    public int subarraysWithKDistinct(int[] A, int K) {
        return atMostKDistinct(A, K) - atMostKDistinct(A, K - 1);
    }

    /**
     * @param A
     * @param K
     * @return 最多包含 K 个不同整数的子区间的个数
     */
    private int atMostKDistinct(int[] A, int K) {
        int len = A.length;
        int[] freq = new int[len + 1];

        int left = 0;
        int right = 0;
        // [left, right) 里不同整数的个数
        int count = 0;
        int res = 0;
        // [left, right) 包含不同整数的个数小于等于 K
        while (right < len) {
            if (freq[A[right]] == 0) {
                count++;
            }
            freq[A[right]]++;
            right++;

            while (count > K) {
                freq[A[left]]--;
                if (freq[A[left]] == 0) {
                    count--;
                }
                left++;
            }
            // [left, right) 区间的长度就是对结果的贡献
            res += right - left;
        }
        return res;
    }
}

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值