###### tags: `Leetcode` `medium` `dynamic programming` `heap` `sliding window` `python`
# 1696. Jump Game VI
## [題目連結]https://leetcode.com/problems/jump-game-vi/
## 題目:
You are given a **0-indexed** integer array ```nums``` and an integer ```k```.
You are initially standing at index ```0```. In one move, you can jump at most ```k``` steps forward without going outside the boundaries of the array. That is, you can jump from index ```i``` to any index in the range ```[i + 1, min(n - 1, i + k)]``` **inclusive**.
You want to reach the last index of the array (index ```n - 1```). Your **score** is the **sum** of all ```nums[j]``` for each index ```j``` you visited in the array.
Return the **maximum score** you can get.
**Example 1:**
```
Input: nums = [1,-1,-2,4,-7,3], k = 2
Output: 7
Explanation: You can choose your jumps forming the subsequence [1,-1,4,3] (underlined above). The sum is 7.
```
**Example 2:**
```
Input: nums = [10,-5,-2,4,0,3], k = 3
Output: 17
Explanation: You can choose your jumps forming the subsequence [10,4,3] (underlined above). The sum is 17.
```
**Example 3:**
```
Input: nums = [1,-5,-20,4,-1,3,-6,-3], k = 2
Output: 0
```
## 解題想法:
* 題目為給一數組,從0-index開始走,每次可以走最多k格,求走到nums[-1],求可獲得最大的得分
* DP動態規劃:
* 暴力法: TLE
* dp+heap: O(NlogN)
* dp+slide window: O(N)
## Python_(Sol1)暴力法: TLE
* 對於i<k:
* dp[i]=nums[i]+max(dp[0],dp[1],.....dp[i-1])
* 對於i>=k:
* dp[i]=nums[i]+max(dp[i-k],dp[i-k+1],...dp[i-1])
* 即其前面k個位置都有機會更新dp[i]
``` python=
class Solution(object):
def maxResult(self, nums, k):
"""
:type nums: List[int]
:type k: int
:rtype: int
"""
dp=[float('-inf') for _ in range(len(nums))]
dp[0]=nums[0]
for i in range(len(nums)):
#對於當前dp[i],其前面k個位置都有機會更新dp[i]
for j in range(max(i-k,0),i):
dp[i]=max(dp[i],dp[j]+nums[i])
return dp[-1]
```
## Python_(Sol2)dp+max_heap: O(NlogN)
* 想法: 使用heap:
* 存pair(Weight,pos)
* 將更新的權重都用heap儲存
* 對於當前位置i,找到符合能跳到的位置(i-k)中,最大的值即可
* 最大值即為heap[0][0]
``` python=
from heapq import heappush,heappop
class Solution(object):
def maxResult(self, nums, k):
"""
:type nums: List[int]
:type k: int
:rtype: int
"""
dp=[float('-inf') for _ in range(len(nums))]
dp[0]=nums[0]
maxHeap=[]
#因為heap預設為min_heap,所以加負號視為max_heap
#即:最大加負號變成最小,優先pop出
heappush(maxHeap,(-dp[0],0)) #(Weight,pos)
for i in range(1,len(nums)):
#當heap中加負號後最小值,其pos不在i-k合理範圍內時
#pop掉
while maxHeap[0][1]<i-k:
heappop(maxHeap)
dp[i]=nums[i]-maxHeap[0][0]
heappush(maxHeap,(-dp[i],i))
return dp[-1]
if __name__=='__main__':
result=Solution()
ans=result.maxResult(nums = [1,-1,-2,4,-7,3], k = 2)
print(ans) #7
```
## Python_(Sol3) dp+slideWindow: O(N)
* 相同類型題目: [239. Sliding Window Maximum](/BojKaeJ1Qo2HPNnEsC-jMg)
* 設一個queue存位置
* window size(即合理範圍)為當前位置-k
* 每次先while確認que中存的位置是否超出合理範圍
* 需注意! que中的pos,對於dp[pos],需抱持為decreasing queue: 遞減的!!
* 即ex: que=[5,3,7], dp[5]>=dp[3]>=dp[7]
``` python=
from collections import deque
class Solution(object):
def maxResult(self, nums, k):
"""
:type nums: List[int]
:type k: int
:rtype: int
"""
dp=[float('-inf') for _ in range(len(nums))]
dp[0]=nums[0]
que=deque()
que.append(0) #存pos
#window size=pos-k
for i in range(1,len(nums)):
#確認que最早的位置是否已經超出合理範圍i-k
while que and que[0]<i-k:
que.popleft()
#更新當前dp[i]
dp[i]=nums[i]+dp[que[0]]
#從尾剔除que中那些dp[que[x]]小於dp[i]的位置x
while que and dp[que[-1]]<=dp[i]:
que.pop()
que.append(i)
return dp[-1]
'''
" while que and que[0]<i-k: "
說明:
* 確認que最早的位置是否已經超出合理範圍i-k
ex: pos=4 k=2 que=[1,2]
則安全範圍最多可以往前探索(4-2)=2,即pos:2,3可以有機會更改當前pos4
所以que[0]=1 超出合理範圍,需pop
" while que and dp[que[-1]]<=dp[i]: "
說明:
從尾剔除que中那些dp[que[x]]小於dp[i]的位置x
意義為: que中的pos需保持對於dp[pos]為decreasing queue: 遞減的!!
因為最尾的一定是最小的dp值,要用肯定不會先用到他
ex: 因為當前的pos(i),最終得到dp[i]
i對於後面i+1...而言,也有機會貢獻自己dp[i]的值
因為每次新的位置選擇que時,一定是選que[0],才有先前最大的dp值
所以對於當前i插入que時,才要比對淘汰掉那些dp值小的前輩,往左邊爬
'''
```