一起养成写作习惯!这是我参与「掘金日新计划 · 4 月更文挑战」的第17天,点击查看活动详情。
说明:文章部分内容及图片出自网络,如有侵权请与我本人联系(主页有公众号:小攻城狮学前端)
作者:小只前端攻城狮、 主页:小只前端攻城狮的主页、 来源:掘金
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
【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];
}
感谢阅读,希望能对你有所帮助,文章若有错误或者侵权,可以在评论区留言或在我的主页添加公众号联系我。
写作不易,如果觉得不错,可以「点赞」+「评论」 谢谢支持❤