zoukankan      html  css  js  c++  java
  • C--3-进阶算法(2)-滑动窗口/单调栈

    C--3-进阶算法(2)-滑动窗口/单调栈

    序号 滑动窗口类题目
    1 滑动窗口的最大值
    2 实现最大值队列
    3 和为s的连续正数序列
    4 最长不含重复字符的子字符串(滑动窗口)
    题目1 滑动窗口的最大值
    标准的滑动窗口解法!!!!!
    class Solution {
    public:
        vector<int> maxSlidingWindow(vector<int>& nums, int k) {
            // 定义一个双端队列
            deque<int> window;
            vector<int> ans;
            if (nums.empty())
            {
                return ans;
            }
            for ( int i = 0 ; i < nums.size(); i++ ) // 对每个位置进行入窗口的操作
            {
                // r 右移策略 
                while ( !window.empty() && nums[window.back()] <= nums[i] )
                {
                    window.pop_back();
                }
                window.push_back( i );
    
                // 每次检查窗口最前面的元素是否过期
                if ( window.front() <= i - k )
                {
                    window.pop_front();
                }
    
                // 窗口大小存储元素
                if ( i  >=  k-1 )
                {
                    ans.push_back( nums[window.front()] );
                }
            }
            return ans;
        }
    };
    
    1. 自己的做法
    class Solution {
    public:
        vector<int> maxSlidingWindow(vector<int>& nums, int k) {
            // 定义一个双端队列
            deque<int> window;
            vector<int> ans;
            if (nums.empty())
            {
                return ans;
            }
            int cur_max = nums[0];
    
            // 把初始窗口填上, 求得当前窗口最值, 注册
    
            int m = k <= ( nums.size()) ? k :nums.size();
    
            for(int i = 0 ;  i < m ; i ++)
            {
                window.push_back(nums[i]);
                cur_max = max( cur_max , window.back());
            }
            ans.push_back(cur_max);
    
            // 窗口大小要是比数组size大,就不用滑动了
            if ( k >= nums.size())
            {
                return ans;
            }
    
            // 从 k 位置开始滑动,前端出一个,后端进一个 
            for (int i = k; i < nums.size() ; i ++ )
            {
                int out = window.front();
                window.pop_front();
                window.push_back(nums[i]);
    
                // ①如果 out 的 数字 不是当前最大值 
                // 只需要用 cur_max 和 in 的值比较就可以确定新的最大值
                if ( out  != cur_max)
                {
                    cur_max = (cur_max > nums[i]) ? cur_max : nums[i];
                }
                //  ②如果 out 的 数字 刚好是当前最大值
                //  分为两种情况
                //  A--> in 的值比 out 的值 大 或相等 
                //  B--> in 的值比 out 小 , 那就只能在队列里遍历求新的最大值了
                else if (out == cur_max)
                {
                    if (nums[i] >= out)
                    {
                        cur_max = nums[i];
                    }else{
                        cur_max = window.front();
                        for (int j = 0 ; j < window.size(); j ++)
                        {
                            cur_max = max(cur_max, window[j]);
                        }
                    }
                }
                ans.push_back(cur_max);
            }
            return ans;
        }
    };
    
    题目2 - II. 队列的最大值

    请定义一个队列并实现函数 max_value 得到队列里的最大值,要求函数max_value、push_back 和 pop_front 的时间复杂度都是O(1)。

    若队列为空,pop_front 和 max_value 需要返回 -1

    示例 1:

    输入:
    ["MaxQueue","push_back","push_back","max_value","pop_front","max_value"]
    [[],[1],[2],[],[],[]]
    输出: [null,null,null,2,1,2]
    示例 2:

    输入:
    ["MaxQueue","pop_front","max_value"]
    [[],[],[]]
    输出: [null,-1,-1]

    class MaxQueue {
    public:
        deque<int> window; // 维持最大值的窗口
        deque<int> queue_;  // 维持基本元素的队列
        MaxQueue() {
        
        }
        
        // 直接返回最大值窗口的front()
        int max_value() {
            if ( window.empty() ){
                return -1 ;
            }else{
                return window.front();
            }
        }
    
        // 从后面插入-> 修改基本队列 和 最大值窗口
        void push_back( int value ) {
    
            queue_.push_back(value);
    
            while ( ! window.empty() && window.back() <= value)
            {
                window.pop_back();
            }
            window.push_back(value);
        }
        
        //  从前端弹出--> 
        int pop_front() {
    
            if ( queue_.empty() )
                return -1;
            int ans = queue_.front();
            queue_.pop_front();
            // ①如果要弹出的元素刚好等于  --> window.pop_front() 
            // ②如果不等于 window,front() ,说明在这个元素插入之后,有比他大的元素进了window ,所以window里不可能有它,不用管了  
            if ( ans == window.front() )
            {
                window.pop_front();
            }
            return ans;
        }
    };
    
    /**
     * Your MaxQueue object will be instantiated and called as such:
     * MaxQueue* obj = new MaxQueue();
     * int param_1 = obj->max_value();
     * obj->push_back(value);
     * int param_3 = obj->pop_front();
     */
    
    题目3 和为s的连续正数序列(滑动窗口)

    输入一个正整数 target ,输出所有和为 target 的连续正整数序列(至少含有两个数)。

    序列内的数字由小到大排列,不同序列按照首个数字从小到大排列。

    示例 1:

    输入:target = 9
    输出:[[2,3,4],[4,5]]
    示例 2:

    输入:target = 15
    输出:[[1,2,3,4,5],[4,5,6],[7,8]]

    class Solution {
    public:
        vector<vector<int>> findContinuousSequence( int target ) {
            vector<vector<int>> ans;
            deque<int> window;
            int num = target >> 1 ;
            int sum = 0 ;
            vector<int> tmp;
            // 遍历到中位数的下一位就可以了, 进队列,
            for ( int i = 1 ; i <= num+1 ; i++)
            {
                window.push_back(i);
                sum = sum + i ; 
                
                // 只要是当前队列和 大于target , 就从前面 pop 
                while( sum > target )
                {
                    sum = sum - window.front();
                    window.pop_front();
                }
    
                if ( sum == target )
                {
                    for( auto k : window )
                    {
                        tmp.push_back(k);
                    }
                    ans.push_back(tmp);
                    tmp.clear();
                }
            }
            return ans;
        }
    };
    
    题目4 最长不含重复字符的子字符串(滑动窗口)

    请从字符串中找出一个最长的不包含重复字符的子字符串,计算该最长子字符串的长度.

    示例 1:
    输入: "abcabcbb"
    输出: 3
    解释: 因为无重复字符的最长子串是 "abc",所以其长度为 3。

    示例 2:
    输入: "bbbbb"
    输出: 1
    解释: 因为无重复字符的最长子串是 "b",所以其长度为 1。

    示例 3:
    输入: "pwwkew"
    输出: 3
    解释: 因为无重复字符的最长子串是 "wke",所以其长度为 3。

    请注意,你的答案必须是 子串 的长度,"pwke" 是一个子序列,不是子串。

    class Solution {
    public:
        int lengthOfLongestSubstring(string s) {
            if( s.empty() || s.size() == 1 )
            {
                return s.size();
            }
            deque<char> window;
            set<char> st;
            int ans = 0 ;
            for ( int  i = 0 ; i < s.size() ; i ++ ) // 每个位置的字符串入队列
            {
                // 如果 st 没有是s[i] 更新 window, st ,ans
                if ( ! st.count(s[i])  )
                {
                    window.push_back(s[i]);
                    st.insert(s[i]);
                    ans   = ans > window.size()  ? ans : window.size() ;
    
                }else if ( st.count(s[i]) )
                {
                    ans   = ans > window.size()  ? ans : window.size() ;
                    // 队列里是s[i]之前的出队列
                    char cur = window.front();               
                    while ( cur != s[i] )
                    {
                        window.pop_front();
                        st.erase(cur);
                        cur = window.front();
                    }
                    window.pop_front();
                    window.push_back(s[i]);
                    st.insert(s[i]);
                }
            }
            return ans;
        }
    };
    
    干啥啥不行,吃饭第一名
  • 相关阅读:
    为了博多
    [JSOI2008]星球大战starwar
    【网络流24题】最小路径覆盖问题
    【中学高级水题本】关路灯
    【网络流24题】分配问题
    【网络流24题】方格取数问题
    【网络流24题】汽车加油行驶
    [洛谷P2057][bzoj1934]善意的投票(最大流)
    LeetCode(38) Count and Say
    LeetCode(36)Valid Sudoku
  • 原文地址:https://www.cnblogs.com/jiangxinyu1/p/12407699.html
Copyright © 2011-2022 走看看