前往
大廳
主題

LeetCode - 1696. Jump Game VI 解題心得

Not In My Back Yard | 2021-09-17 00:00:03 | 巴幣 0 | 人氣 391

題目連結:


題目意譯:
你被給定一個索引值從 0 開始的整數陣列 nums 以及一整數 k 。

你一開始站在索引值 0 的位置。在一次移動中,你在不跑出陣列邊界的情況下最多可以往前 k 步。也就是說,你可以從索引值 i 跳到位於範圍 [i + 1, min(n - 1, i + k)] (含端點)的任意索引值上。

你想要抵達陣列的最後一個位置(索引值 n - 1)。你的分數為你在陣列中拜訪的所有索引值 j 之 nums[j] 之總和。

回傳你所能得到的最大分數值。

限制:
1 ≦ nums.length 、 k ≦ 10 ^ 5
-10 ^ 4 ≦ nums[i] ≦ 10 ^ 4



範例測資:
範例 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


解題思維:
這題可以用動態規劃(Dynamic Programming,DP)來求得答案。令 D[i] 為 nums[0] 到 nums[i] 所能獲得的最大分數。而很明顯地,遞迴式為
D[0] = nums[0]、
D[i] = nums[i] + max(D[0], D[1], ……, D[i - 1]) 對於 i < k、
D[i] = nums[i] + max(D[i - k], D[i - k + 1], ……, D[i - 1]) 對於 i ≧ k 。
也就是每個位置 i 的最大分數值都是往前最多 k 個位置去找最大分數值,然後將該值加上 nums[i] 即可求得。



因此接下來的問題是:要怎麼快速地求得往前最多 k 個位置中的最大值(畢竟不能直接暴力去找)?

而我們可以使用雙端佇列 Q(Double-Ended Queue,簡稱 deque)來儲存前 k 個位置的索引值,而我們要維護 Q 使得 Q 中每個索引值對應的數值皆大於等於下一個索引值對應的數字。

如此一來,Q.front()(即 Q 的左側/前端)這個索引值對應的數值即是前 k 個位置裡面最大者;而 Q.back()(即 Q的右側/尾端)為最小值。

接著我們從 i = 0 開始掃到 i = nums.length - 1。對於每個 i ,令 D[i] = Q.front() + nums[i](如果 Q 為空則為,nums[i] 本身)。

然後判斷 Q 是否非空且 D[Q.back()] 是否小於 D[i],如果是則代表 D[Q.back()] 絕對不可能在求值過程中派上用場(因為它暨比 D[i] 小,又比 i 接近 i - k 這個範圍(也就是比 D[i] 更早會離開「前 k 個位置」)),因此我們將 Q.back() 這個元素移除掉。重複此步驟直到條件之一不符合為止。

此時我們將索引值 i 推入到 Q 的尾端。然後判斷 Q.front() + k 是否等於 i。如果是則代表當我們進行到下一個索引值 i + 1 時,此時的最大值 Q.front() 就不再有用了(超出前 k 個之範圍)。因此我們此時需要將 Q.front() 移除掉。

因此到最後便可以求得 D[nums.length - 1] 之值,而此即為所求。




此次分享到此為止,如有任何更加簡潔的想法或是有說明不清楚之地方,也煩請各位大大撥冗討論。

創作回應

更多創作