---
# System prepended metadata

title: 1696. Jump Game VI
tags: [sliding window, heap, Leetcode, medium, python, dynamic programming]

---

###### 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值小的前輩，往左邊爬
'''
                
```