1696. 跳跃游戏 VI(单调栈单调队列)

给你一个下标从 0 开始的整数数组 nums 和一个整数 k 。

一开始你在下标 0 处。每一步,你最多可以往前跳 k 步,但你不能跳出数组的边界。也就是说,你可以从下标 i 跳到 [i + 1, min(n - 1, i + k)] 包含 两个端点的任意位置。

你的目标是到达数组最后一个位置(下标为 n - 1 ),你的 得分 为经过的所有数字之和。

请你返回你能得到的 最大得分 。

 

示例 1:

输入:nums = [1,-1,-2,4,-7,3], k = 2
输出:7
解释:你可以选择子序列 [1,-1,4,3] (上面加粗的数字),和为 7 。

示例 2:

输入:nums = [10,-5,-2,4,0,3], k = 3
输出:17
解释:你可以选择子序列 [10,4,3] (上面加粗数字),和为 17 。

示例 3:

输入:nums = [1,-5,-20,4,-1,3,-6,-3], k = 2
输出:0

 

提示:

  •  1 <= nums.length, k <= 105
  • -104 <= nums[i] <= 104
 
这个题就是一个滑动窗口的变式
const int maxn=1e6+100;
class Solution {
public:
    int f[maxn];
    int q[maxn];
    int maxResult(vector<int>& nums, int k) {
        memset(f,0,sizeof(f));
        int h=0,t=0;
        int n=nums.size();
        f[0]=nums[0];
        q[0]=0;
        for(int i=1;i<n;i++){
            while(h<=t&&q[h]+k<i) h++;
            f[i] = f[q[h]] + nums[i];
            while(h<=t&&f[i]>=f[q[t]]) t--;
            q[++t]=i;
        }
        return f[n-1];
    }
};

双端队列的代码:

class Solution {
public:
    int maxResult(vector<int>& nums, int k) {
        int n = nums.size();
        vector<int> f(n);
        f[0] = nums[0];
        deque<int> q;
        q.push_back(0);
        for (int i = 1; i < n; i ++ ) {
            while (q.front() < i - k) q.pop_front();
            f[i] = f[q.front()] + nums[i];
            while (q.size() && f[q.back()] <= f[i]) q.pop_back();
            q.push_back(i);
        }
        return f[n - 1];
    }
};

 


posted @ 2021-05-20 21:15  lipu123  阅读(68)  评论(0)    收藏  举报