🌈【LeetCode 1696. 跳跃游戏 VI 】- JavaScript(动态规划+优化)

182 阅读2分钟

一起养成写作习惯!这是我参与「掘金日新计划 · 4 月更文挑战」的第17天,点击查看活动详情


说明:文章部分内容及图片出自网络,如有侵权请与我本人联系(主页有公众号:小攻城狮学前端)

作者:小只前端攻城狮、 主页:小只前端攻城狮的主页、 来源:掘金

GitHub:P-J27、 CSDN:PJ想做前端攻城狮

著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。


【LeetCode 1696. 跳跃游戏 VI 】- JavaScript(动态规划+优化)

题目描述

给你一个下标从 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 。

思路分析:

下意识告诉我这题是dp,推个状态方程:dp[i] = Math.max(dp[i-1]...dp[i-k]) + nums[i]

然后我就冲了,然后就TE了。所以还得记忆化处理一下。

动态规划+单调队列

上面也说了直接dp,只能吃TE。所以这里用上优先队列,可以让求窗口Max的过程记忆化,避免重复的计算。

维护一个单调队列进行动态规划 对于点i,如果在点i前面有两个点a,b(a<b),并且a,b都可以跳到i,如果 在b处得到分数比a处分数还要多,这样就不用一直去查a点。

核心要维护好区间 start[max(0, i - k)],单调队列中需要移除 dp[start - 1] 的值

var maxResult = function(nums, k) {
    let queue=[]
    for(let i=0; i<nums.length-1; i++){
        const num = nums[i]
        while(queue[queue.length-1]<num){
            queue.pop()
        }
        queue.push(num)
        if(i>=k&&nums[i-k]===queue[0]){
            queue.shift()
        }
        nums[i+1]+=queue[0]||0
    }
    return nums.pop()
};

动态规划+贪心

这种思路也快的,

dp[i]表示跳到i的最大得分,dp[i]=nums[i]+fmax(dp[i-1], dp[i-k]) 如果哪个数字为正数, 需要跳到对应位置

int maxResult(int* nums, int numsSize, int k){
    int dp[numsSize];
    int i, j, max;
    dp[0] = nums[0];
    
    for (i = 1; i < numsSize; i++) {
        max = INT_MIN;
        for (j = i - 1; j >= 0 && i - j <= k; j--) {
            max = fmax(max, dp[j]);
            if (nums[j] > 0) { /* 为正的石头需要跳过去 */
                break;
            }
        }
        dp[i] = nums[i] + max;
    }
    return dp[numsSize - 1];
}

感谢阅读,希望能对你有所帮助,文章若有错误或者侵权,可以在评论区留言或在我的主页添加公众号联系我。

写作不易,如果觉得不错,可以「点赞」+「评论」 谢谢支持❤