0
点赞
收藏
分享

微信扫一扫

力扣 1696. 跳跃游戏 VI(c++)

蛇发女妖 2022-02-04 阅读 167

1696. 跳跃游戏 VI - 力扣(LeetCode) (leetcode-cn.com)

在这里插入图片描述

结果

题意

从数组中从左到右选取数字,下标为0和下标为n-1的为必选。从你上一次选的位置往后选k个数字中的某一个。

第一次的上一次是? 因为0为必选,所以第一次选下标为1~k的数字。

解析

因为要求得分最大,所以每一步我们都希望是当前最大的,这样到终点才能是最大得分。

当前的分数 = 之前的分数 + 数组该位置的数值

数组该位置的数值是无法改变的,所以要让当前的分数最大,就要让之前的分数最大,也就是选取前K个得分最大的那一个

dp[i] = max(nums[i-k]~nums[i-1])

前面这个最大有很多种方法得到。

最容易想到的就是遍历 nums[i-k] ~ nums[i-1] ,并记录最大值

maxn = nums[i-1];
for(int j=i-k;j<i;j++){
    maxn = max(maxn, nums[j]);
}

但是我试过了,超时。

所以这里用到滑动窗口的思想,使用的数据结构是:优先队列(堆)

蓝色的是k = 2(假设一开始在7这个位置)

那么要选取前2个中的最大值,是5

下一步,当前位置来到6,选取前两个最大值,是7

下一步,来到3,选取最大值7

下一步,来到8,选取最大值6

可以观察到每一次的最大值不一定就是下一次的最大值,甚至不会出现在下一次的比较范围

比如说5只会在15和57这两个窗口中存在。

所以比较时不仅要关注数值,也要关注位置,位置不能在 i-k 之前

  • 为什么滑动窗口节省时间?

因为如果最大值是在比较范围的中间时,其余的是不需要再比较的。

比如 7 3 5 8 2 4 6 | 9

这里用 | 表示 i 在9这个位置 ,其中k=6(刚好到3)

显然最大值是8,下一次比较时只需要比较8和9,而其他的一定不会比8大(否则8就不是窗口内的最大值了)

而最大值是边缘时,确实需要再比较一次,因为堆的特性,得到窗口内的最大值很快。

代码

  • len 指的是数组的大小
  • num 是自定义数据结构,其中val表示数值,idx表示该数值的位置
struct num{
    num(int a, int b){
        this->val = a;
        this->idx = b;
    }
    int val;
    int idx;
};
  • cmp是重写的比较器,因为堆中是我们自定义的数据类型,因为要大根堆,所以判定条件是 <=
struct cmp{
    bool operator()(num n1, num n2){
        return n1.val<=n2.val;
    }
};
class Solution {
public:
    int len;
    int maxResult(vector<int>& nums, int k) {
        struct num{
            num(int a, int b){
                this->val = a;
                this->idx = b;
            }
            int val;
            int idx;
        };
        struct cmp{
            bool operator()(num n1, num n2){
                return n1.val<=n2.val;
            }
        };
        len = nums.size();
        vector<int> dp(len);
        dp[0] = nums[0];
        priority_queue<num,vector<num>, cmp> heap;
        for(int i=1;i<len;i++){
            if(!heap.empty()){
                // 当前滑动窗口的最大值
                num top = heap.top();
                // 如果滑动窗口的最大值已经超出了 i-k 的范围,那么将这个最大值弹出(它已经无效了)
                while(!heap.empty()&&top.idx<i-k){
                    heap.pop();
                    top = heap.top();
                }
            }
            // 将前一个位置的值放入堆中
            heap.push(num(dp[i-1], i-1));
            dp[i] = heap.top().val;
            dp[i] += nums[i];
        }
        return dp[len-1];
    }
};
举报

相关推荐

0 条评论