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 <= 10^5
-10^4 <= nums[i] <= 10^4
思路:
1.动态规划:双重循环,动态规划,dp[i]代表跳到i位置获得的最大分值;
递归式:dp[i]=max(dp[i],max(dp[j]+nums[i])) 其中j∈(i-k,i)
代码:
class Solution:
def maxResult(self, nums: List[int], k: int) -> int:
n = len(nums)
map = [-10 ** 10] * n
map[0] = nums[0]
for i in range(1,n):
for j in range(max(i-k,0),i):
map[i] = max(map[i],map[j] + nums[i])
print(map)
return map[n-1]
超时了!
仔细想一想,这个复杂度其实体现在了对于i位置前k个位置里的最大得分的计算上,联想一下,这个其实和滑动窗口类似,因此我们借鉴之前滑动窗口的方法来确定该值,降低时间复杂度!
class Solution:
def maxResult(self, nums: List[int], k: int) -> int:
n = len(nums)
f = [0] + [-inf]*n
q = deque()
for i,x in enumerate(nums,1):
# 保持窗口大小为k
while q and i - q[0] > k:
q.popleft()
# 更新答案
f[i] = f[q[0]] + x if q else x
# 去除窗口内无用数据
while q and f[q[-1]] <= f[i]:
q.pop()
# 入队
q.append(i)
return f[-1]