• LeetCode 239. Sliding Window Maximum(Hard)


    题目

    题意:在一个固定长度的滑动窗口里,计算窗口里的最大值,并且这个滑动窗口每次移动一个。

    题解:首先想到的是set,窗口滑动,就是删除一个数,增加一个数,都是O(logn)的效率

    80ms

    class Solution {
    public:
        multiset<int> m;
        vector<int> ans;
        vector<int> maxSlidingWindow(vector<int>& nums, int k) {
            
            if(k==0||nums.size()==0)
                return ans;
            
            for(int i=0;i<k;i++)
            {
                m.insert(nums[i]);
            }
            
            ans.push_back(*prev(m.end()));
            
            for(int i=k;i<nums.size();i++)
            {
                multiset<int>::iterator it = m.find(nums[i-k]);
                m.erase(it);
                m.insert(nums[i]);
                ans.push_back(*prev(m.end()));
            }
            return ans;
        }
    };
    

    我们还可以用单调栈,实现在窗口滑动的过程中O(1)的效率得到最小值。
    单调栈是一个单调递减的栈,入栈,也就是滑动时,如果栈顶元素比它小,则出栈,直到栈顶元素大于等于新元素。与此同时,栈低元素需要判断它的下标是否小于窗口左边,如果小于,栈底也要前进一格。
    严格上来说,这也不是栈。
    每次滑动窗口时,最大值显然是栈低元素,而进栈的操作,平均是O(1)的效率
    60ms

    class Solution {
    public:
        int s1[100005];
        int s2[100005];
        int bottom1;
        int bottom2;
        int top1;
        int top2;
        vector<int> ans;
        vector<int> maxSlidingWindow(vector<int>& nums, int k) {
            
            if(k==0||nums.size()==0)
                return ans;
            
            for(int i=0;i<k;i++)
            {
                EnStack(nums[i],i);
            }
            
            ans.push_back(s1[bottom1]);
            
            for(int i=k;i<nums.size();i++)
            {
                EnStack(nums[i],i);
                if(s2[bottom2]==i-k)
                {
                    bottom2++;
                    bottom1++;
                }
                
                ans.push_back(s1[bottom1]);
            }
            return ans;
        }
        
        void EnStack(int x,int pos)
        {
            if(top1==0)
            {
                s1[top1++]=x;
                s2[top2++]=pos;
            }
            else
            {
                while(top1!=bottom1&&s1[top1-1]<x)
                {
                    top1--;
                    top2--;
                }
                
                s1[top1++]=x;
                s2[top2++]=pos;
            }
        }
    };
    

    看了题解,发现还有更好的方法,就是实现维护两个数组,left数组表示窗口里从左开始的最大值,right数组表示从右开始的最大值。
    52ms

    class Solution {
    public:
        int left[100005];
        int right[100005];
        vector<int> ans;
        vector<int> maxSlidingWindow(vector<int>& nums, int k) {
            
            if(k==0||nums.size()==0)
                return ans;
            
            for(int i=0,j=nums.size()-1;i<nums.size()&&j>=0;i++,j--)
            {
                if(i%k==0)
                    left[i]=nums[i];
                else
                    left[i]=max(nums[i],left[i-1]);
                
                if((j+1)%k==0||j==nums.size()-1)
                {
                    right[j]=nums[j];
                }
                else
                    right[j]=max(nums[j],right[j+1]);
            }
            
            for(int i=0;i<nums.size()-k+1;i++)
            {
                ans.push_back(max(right[i],left[i+k-1]));
            }
            
            return ans;
        }
    };
    
  • 相关阅读:
    Linux 虚拟机虚拟网卡问题导致无法连接问题
    使用 Load Balancer,Corosync,Pacemaker 搭建 Linux 高可用集群
    如何在 Linux 虚拟机上扩展根文件系统
    Linux 虚拟机中配置 GNOME + VNC
    在 Linux 中使用 Azure Premium 存储的基本优化指南
    如何为运行的 ARM Linux 启用 LAD2.3 版本的诊断扩展
    如何解决 Linux 虚拟机磁盘设备名不一致的问题
    Java 调用 Rest api 设置经典 Linux 虚拟机的实例启停
    CentOS: 将虚拟机迁移到 Azure (以阿里云为例)
    Linux 虚拟机的计划维护
  • 原文地址:https://www.cnblogs.com/dacc123/p/12409995.html
Copyright © 2020-2023  润新知