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;
    }
};
干啥啥不行,吃饭第一名
原文地址:https://www.cnblogs.com/jiangxinyu1/p/12407699.html