题目:
给你一个下标从 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
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/jump-game-vi
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
题解:
class Solution {
public:
int maxResult(vector<int>& nums, int k) {
deque<int> dq;
int n = nums.size();
vector<int> dp(n,0);
// 起点作为dp起点
dp[0] = nums[0];
dq.push_back(0);
for(int i=1;i<n;i++){
// 维护单调队列的长度,就是当前元素加k可以够到
if(!dq.empty()&&dq.front()+k<i){
dq.pop_front();
}
// 写入当前的dp
dp[i] = dp[dq.front()] + nums[i];
// 维护队列的单调性,小于当前dp[i]的都删掉,保证了dp.front()是最大的
while(!dq.empty()&&dp[dq.back()]<=dp[i]){
// 删除
dq.pop_back();
}
// 将当前的下标入队
dq.push_back(i);
}
return dp[n-1];
}
};
思路:
我开始的时候是这样的!
class Solution {
public:
int maxResult(vector<int>& nums, int k) {
int n = nums.size()-1;
vector<int> memo(n+1,1000000);
int ans = dfs(n,k,nums,memo);
return ans;
}
int dfs(int n,int k,vector<int>& nums,vector<int>& memo){
//结束条件
if(n==0) return nums[0];
if(memo[n]!=1000000) return memo[n];
int res = -1000000;
for(int i=1;i<=k;i++){
//跳过不合法的
if(n-i<0) continue;
//遍历跳1到k步
res=max(res,dfs(n-i,k,nums,memo)+nums[n]);
}
memo[n] = res;
return res;
}
};
但是怎么会这么简单,超时了!
res=max(res,dfs(n-i,k,nums,memo)+nums[n]);
这里太多冗余的比较了!
然后我就看见别人的单调队列优化dp。然后参考着写出了题解
还算明白这个题解,但是自己还没没自己的思路!