zoukankan      html  css  js  c++  java
  • 窗口的最大值与最小值更新结构(滑动窗口)

    使用单调队列解决滑动窗口的最大值

    #include <iostream>
    #include <deque>
    #include <vector>
    using namespace std;
    class MonotonicQueue { // 构建单调队列
    private:
            deque<int> data;
    public:
            void push(int n) {
                   while (!data.empty() && data.back() < n) {
                           data.pop_back();
                   }
                   data.push_back(n);
            }
            int max() {
                   return data.front();
            }
            void pop(int n) {
                   if (!data.empty() && data.front() == n) {
                           data.pop_front();
                   }
            }
    };
    class Solution {
    public:
            // 使用单调队列
            vector<int> maxWindowSlide(vector<int>& nums, int k) {
                   vector<int> res;
                   MonotonicQueue window;
                   for (int i = 0; i < nums.size(); i++) {
                           if (i < k - 1) {
                                  window.push(nums[i]);
                           }
                           else {
                                  window.push(nums[i]);
                                  res.push_back(window.max());
                                  window.pop(nums[i-k+1]);
                           }
                   }
                   return res;
            }
            /*
            遍历数组,将数存放在双向队列中,并用L,R来标记窗口的左边界和右边界。队列中保存的并不是真的数,
            而是该数值对应的数组下标位置,并且数组中的数要从大到小排序。如果当前遍历的数比队尾的值大,则需要弹出队尾值,
            直到队列重新满足从大到小的要求。刚开始遍历时,L和R都为0,有一个形成窗口的过程,此过程没有最大值,L不动,R向右移。
            当窗口大小形成时,L和R一起向右移,每次移动时,
            判断队首的值的数组下标是否在[L,R]中,如果不在则需要弹出队首的值,当前窗口的最大值即为队首的数。
            */
            // 使用双端队列
            vector<int> maxWindowSlide2(vector<int>& nums, int k) {
                   vector<int> res;
                   deque<int> dq;
                   int i = 0;
                   int j = 0;
                   while(i< nums.size()) {
                           while (j < nums.size()) {
                                  while (!dq.empty() && nums[dq.back()] < nums[j]) {
                                          dq.pop_back();
                                  }
                                  dq.push_back(j);
                                  j++;
                           }
                           if (dq.front() <= i-k) {  // 判断当前队列中队首的值是否有效(过期)
                                  dq.pop_front();
                           }
                           if (i >= k-1) {    // 当窗口长度为k时 保存当前窗口中最大值
                                  res.push_back(nums[dq.front()]);
                           }
                           i++;
                   }
                   return res;
            }
    };
    

     这里在记录一个别人的答案(双端队列解决),简短不失优雅。 

    class Solution2 {
    public:
            vector<int> maxInWindows(const vector<int>& num, unsigned int size)
            {
                   vector<int> res;
                   deque<int> s;
                   for (unsigned int i = 0; i < num.size(); ++i) {
                           while (s.size() && num[s.back()] <= num[i])//从后面依次弹出队列中比当前num值小的元素,同时也能保证队列首元素为当前窗口最大值下标
                                  s.pop_back();
                           while (s.size() && i - s.front() + 1 > size)//当当前窗口移出队首元素所在的位置,即队首元素坐标对应的num不在窗口中,需要弹出
                                  s.pop_front();
                           s.push_back(i);//把每次滑动的num下标加入队列
                           if (size && i + 1 >= size)//当滑动窗口首地址i大于等于size时才开始写入窗口最大值
                                  res.push_back(num[s.front()]);
                   }
                   return res;
            }
    };
    void main() {
            Solution S;
            vector<int> nums{ 9,7,10,5,8,3,6 };
            int k = 3;
            //vector<int> res = S.maxWindowSlide(nums, k);
            //for (auto s : res) {
            //      cout << s;
            //}
            //cout << endl;
            vector<int> res2 = S.maxWindowSlide2(nums, k);
            for (auto n : res2) {
                   cout << n;
            }
    }
    

      

  • 相关阅读:
    t体育课了
    Scrapy、Scrapy-redis组件
    爬虫案例(js动态生成数据)
    UA池和代理池
    增量式爬虫(简易)
    基于scrapy-redis分布式爬虫(简易)
    全栈爬取-Scrapy框架(CrawlSpider)
    scrapy中selenium的应用
    scrapy框架的日志等级和请求传参
    scrapy框架之递归解析和post请求
  • 原文地址:https://www.cnblogs.com/E-Dreamer-Blogs/p/12813776.html
Copyright © 2011-2022 走看看