DP動態規劃 深入淺出 以Range Sum Query Immutable 區間和 為例

更新於 發佈於 閱讀時間約 6 分鐘
raw-image

題目敘述

在學習過比較基本的DP模型 費式數列爬樓梯找零錢...等之後,來看一個比較進階而且實用的DP模型,前綴和(Prefix sum),可以再加以延伸推廣,來計算 區間和(Range Sum)。


詳細的題目可在這裡看到

題目會給定一個輸入陣列,並且定義好function界面,要求我們實作出sumRange(left, right) 區間和的功能。


測試範例

Example 1:

Input
["NumArray", "sumRange", "sumRange", "sumRange"]
[[[-2, 0, 3, -5, 2, -1]], [0, 2], [2, 5], [0, 5]]
Output
[null, 1, -1, -3]

Explanation
NumArray numArray = new NumArray([-2, 0, 3, -5, 2, -1]);
numArray.sumRange(0, 2); // return (-2) + 0 + 3 = 1
numArray.sumRange(2, 5); // return 3 + (-5) + 2 + (-1) = -1
numArray.sumRange(0, 5); // return (-2) + 0 + 3 + (-5) + 2 + (-1) = -3

約束條件

Constraints:

  • 1 <= nums.length <= 10^4

輸入陣列長度介於1 ~ 10^4 之間。

  • -10^5 <= nums[i] <= 10^5

每個陣列元素界於 -10^5 ~ 10^5 之間。

  • 0 <= left <= right < nums.length

動態測試給的區間一定是合法區間。

  • At most 10^4 calls will be made to sumRange.

動態測試時,最多有10^4次函式呼叫。


同樣地,先走過一遍解題框架可分為三大步驟,藉此鞏固解題基礎。

定義狀態 [我在哪裡]

我們可以透過前綴和Prefix sum,來間接求出 區間和Range sum

令PrefixSum[0] = nums[0]

PrefixSum[i] = nums[0] + nums[1] + ... +nums[i] 從第0項~第i項的總和



2. 定義狀態轉移關係式(通則) [我從哪裡來] => [答案從哪裡推導而來]

PrefixSum 前綴和本身的狀態轉移如下

PrefixSum[i]

= nums[0] + nums[1] + ... +nums[i] 從第0項~第i項的總和

= PrefixSum[i-1] +nums[i]

= [ 從第0項~第(i-1)項的總和 ]+第i項

= 從第0項~第i項的總和


raw-image

接著,可以根據定義推導出

RangeSum(left, right) 區間[left, right]的元素總和

= PrefixSum( right ) - PrefixSum( left - 1 )

= nums[left] + nums[left+1] + ... + nums[right]

留意邊界索引的處理


3. 釐清初始狀態(終止條件) [第一步怎麼走,怎麼出發的]

PrefixSum 前綴和的初始條件就是第0項 = PrefixSum[0] = nums[0]


RangeSum 區間和呢?

類似的,邊界條件也發生在left = 0的時候,這時候左邊已經沒有別的元素了,

此時,PrefixSum[right] = RangeSum(left, right)

直接返回 PrefixSum[right] 即可


程式碼

class NumArray:

 def __init__(self, nums: List[int]):
  
  self.size = len(nums)
  

  # build prefix sum table when input nums is valid
  self.s = [ 0 for _ in range(self.size) ]

  self.s[0] = nums[0]

  # s[k] = nums[0] + ... + nums[k]
  # s[k] = s[k-1] + nums[k]
  for k in range(1,self.size):
   self.s[k] = self.s[ k-1 ] + nums[ k ]
  

 def sumRange(self, left: int, right: int) -> int:
  

  # lookup table from prefix sum table, s
  if left == 0:
   return self.s[ right ]
  else:
   return self.s[ right ]-self.s[ left-1 ]

複雜度分析

時間複雜度:

O( n ) : init() 初始化的時候,需要計算PrefixSum的表格
O( 1 ) : sumRange(left, right),直接查表,做個減法,就可以得到區間和的答案。

空間複雜度:

O( n ) : init() 初始化的時候,需要建立PrefixSum的表格,長度為O(n)
O( 1 ) : sumRange(left, right),直接查表,就可以得到區間和的答案。


Reference:

[1] Python/JS/Go/C++ by prefix sum. [ With explanation ] - Range Sum Query - Immutable - LeetCode

avatar-img
90會員
425內容數
由有業界實戰經驗的演算法工程師, 手把手教你建立解題的框架, 一步步寫出高效、清晰易懂的解題答案。 著重在讓讀者啟發思考、理解演算法,熟悉常見的演算法模板。 深入淺出地介紹題目背後所使用的演算法意義,融會貫通演算法與資料結構的應用。 在幾個經典的題目融入一道題目的多種解法,或者同一招解不同的題目,擴展廣度,並加深印象。
留言0
查看全部
avatar-img
發表第一個留言支持創作者!
上次學過2D DP入門題目 Unique Path,接著來看進階一點的高度關聯延伸題 Unique Path II,這次板子上多了障礙物。 題目給定我們一個棋盤的高與寬,起點固定在左上角,終點固定在右下角。 每一步只能選擇往右走一格,或者往下走一格,不能回頭。 有障礙物的格子無法通過。
如同這個Dynamic programming 深入淺出系列的開始, 在經過比較簡單的入門題(Coin Change)之後, 來看比較進階的二維DP題目Unique Path
爬到頂樓的最小成本, 這題算是前面那題Climbing stairs的變形題,有點小變化, 但是稍微想一下還是能推導出來,算是很好的一維動態規劃1D DP練習題。
今天再來看一題入門的2D DP題目: 巴斯卡三角形 再次複習Dynamic programming的解題框架,可分為三大步驟 1.定義狀態 [我在哪裡] 2. 定義狀態轉移關係式(通則) [我從哪裡來] => [答案從哪裡推導而來] 3. 釐清初始狀態(也可以說是遞
這題乍看之下是新題目,但仔細一想, 其實只是前面介紹過的費式數列的小變形而已,解題思想基本不變。 題目說每次可以爬一階樓梯或兩階樓梯,問爬到n階的方法數是多少。
上次學過2D DP入門題目 Unique Path,接著來看進階一點的高度關聯延伸題 Unique Path II,這次板子上多了障礙物。 題目給定我們一個棋盤的高與寬,起點固定在左上角,終點固定在右下角。 每一步只能選擇往右走一格,或者往下走一格,不能回頭。 有障礙物的格子無法通過。
如同這個Dynamic programming 深入淺出系列的開始, 在經過比較簡單的入門題(Coin Change)之後, 來看比較進階的二維DP題目Unique Path
爬到頂樓的最小成本, 這題算是前面那題Climbing stairs的變形題,有點小變化, 但是稍微想一下還是能推導出來,算是很好的一維動態規劃1D DP練習題。
今天再來看一題入門的2D DP題目: 巴斯卡三角形 再次複習Dynamic programming的解題框架,可分為三大步驟 1.定義狀態 [我在哪裡] 2. 定義狀態轉移關係式(通則) [我從哪裡來] => [答案從哪裡推導而來] 3. 釐清初始狀態(也可以說是遞
這題乍看之下是新題目,但仔細一想, 其實只是前面介紹過的費式數列的小變形而已,解題思想基本不變。 題目說每次可以爬一階樓梯或兩階樓梯,問爬到n階的方法數是多少。
你可能也想看
Google News 追蹤
Thumbnail
隨著理財資訊的普及,越來越多台灣人不再將資產侷限於台股,而是將視野拓展到國際市場。特別是美國市場,其豐富的理財選擇,讓不少人開始思考將資金配置於海外市場的可能性。 然而,要參與美國市場並不只是盲目跟隨標的這麼簡單,而是需要策略和方式,尤其對新手而言,除了選股以外還會遇到語言、開戶流程、Ap
Thumbnail
嘿,大家新年快樂~ 新年大家都在做什麼呢? 跨年夜的我趕工製作某個外包設計案,在工作告一段落時趕上倒數。 然後和兩個小孩過了一個忙亂的元旦。在深夜時刻,看到朋友傳來的解籤網站,興致勃勃熬夜體驗了一下,覺得非常好玩,或許有人玩過了,但還是想寫上來分享紀錄一下~
Thumbnail
介紹pygame支援的向量運算,以及向量的減法、乘法、除法實際上是怎麼計算的。
Thumbnail
本文詳細介紹了Python中的各種資料型別,包括整數、字串、清單、元組、集合和字典,並提供了相關的操作範例。此外,還解釋了如何在Python中定義和操作變數,包括如何同時對多個變數進行賦值。
Thumbnail
本文章介紹如何利用PD Arrays和ICT 2022 Model在虛擬貨幣市場找到交易機會。透過定義日線起點、畫出日內折溢價區和尋找潛在PD Arrays,建立起完整的交易系統。文章內容包含具體的交易策略和步驟及實例說明和分析。血哥分享自己的交易經驗,並提供交易員培訓計劃,邀請讀者一起加入學習。
Thumbnail
分享在網路上看到的陣列題目。通常 for...of 的 value 是陣列中的每個值,那如果我們在迭代中對陣列操作會發生什麼事? 題目來源:https://x.com/_jayphelps/status/1774640511158022335?s=20
在求學階段,你已經對代數的計算熟到不能再熟,所以變數(variable)對你來說應該不至於太陌生,先來看看以下這個例子:   
(略),array 是用來將陣列的值進行累加,我們來看看怎麼怎麼達成吧: Given an integer array nums, a reducer function fn, and an initial value init, return the final result obtained
Thumbnail
今天來聊聊一個新手必學的兩個函式:SUMIF 跟 SUMIFS! 簡單來說,SUMIF 跟 SUMIFS 都是用條件來篩選值、再做加總的函式,你可以看成是 SUM 跟 IF / IFS 的結合。
Thumbnail
SUMIF是EXCEL中一個超級實用的統計函數,他可以依據指定的關鍵字進行加總。 SUMIF有條件加總 函數說明=SUMIF(條件範圍,條件,加總範圍) 但如果遇到很多個資料範圍,大多數的人就會使用很多個SUMIF計算後再相加,如下範例所示。 其實這樣多範圍的資料不需要3個SUMIF,
Thumbnail
在Python中,數值運算非常直觀,你可以使用標準的數學運算符號進行基本的數值運算。以下是一些基本的數值運算: 進行計算時,按照「先乘除後加減」的規則,並優先計算小括號刮起來的運算式。 print('答案:' ,(1+1)*2) #​答案: 4 復合型態的運算子 指定運算子 = 若是結合算術
Thumbnail
隨著理財資訊的普及,越來越多台灣人不再將資產侷限於台股,而是將視野拓展到國際市場。特別是美國市場,其豐富的理財選擇,讓不少人開始思考將資金配置於海外市場的可能性。 然而,要參與美國市場並不只是盲目跟隨標的這麼簡單,而是需要策略和方式,尤其對新手而言,除了選股以外還會遇到語言、開戶流程、Ap
Thumbnail
嘿,大家新年快樂~ 新年大家都在做什麼呢? 跨年夜的我趕工製作某個外包設計案,在工作告一段落時趕上倒數。 然後和兩個小孩過了一個忙亂的元旦。在深夜時刻,看到朋友傳來的解籤網站,興致勃勃熬夜體驗了一下,覺得非常好玩,或許有人玩過了,但還是想寫上來分享紀錄一下~
Thumbnail
介紹pygame支援的向量運算,以及向量的減法、乘法、除法實際上是怎麼計算的。
Thumbnail
本文詳細介紹了Python中的各種資料型別,包括整數、字串、清單、元組、集合和字典,並提供了相關的操作範例。此外,還解釋了如何在Python中定義和操作變數,包括如何同時對多個變數進行賦值。
Thumbnail
本文章介紹如何利用PD Arrays和ICT 2022 Model在虛擬貨幣市場找到交易機會。透過定義日線起點、畫出日內折溢價區和尋找潛在PD Arrays,建立起完整的交易系統。文章內容包含具體的交易策略和步驟及實例說明和分析。血哥分享自己的交易經驗,並提供交易員培訓計劃,邀請讀者一起加入學習。
Thumbnail
分享在網路上看到的陣列題目。通常 for...of 的 value 是陣列中的每個值,那如果我們在迭代中對陣列操作會發生什麼事? 題目來源:https://x.com/_jayphelps/status/1774640511158022335?s=20
在求學階段,你已經對代數的計算熟到不能再熟,所以變數(variable)對你來說應該不至於太陌生,先來看看以下這個例子:   
(略),array 是用來將陣列的值進行累加,我們來看看怎麼怎麼達成吧: Given an integer array nums, a reducer function fn, and an initial value init, return the final result obtained
Thumbnail
今天來聊聊一個新手必學的兩個函式:SUMIF 跟 SUMIFS! 簡單來說,SUMIF 跟 SUMIFS 都是用條件來篩選值、再做加總的函式,你可以看成是 SUM 跟 IF / IFS 的結合。
Thumbnail
SUMIF是EXCEL中一個超級實用的統計函數,他可以依據指定的關鍵字進行加總。 SUMIF有條件加總 函數說明=SUMIF(條件範圍,條件,加總範圍) 但如果遇到很多個資料範圍,大多數的人就會使用很多個SUMIF計算後再相加,如下範例所示。 其實這樣多範圍的資料不需要3個SUMIF,
Thumbnail
在Python中,數值運算非常直觀,你可以使用標準的數學運算符號進行基本的數值運算。以下是一些基本的數值運算: 進行計算時,按照「先乘除後加減」的規則,並優先計算小括號刮起來的運算式。 print('答案:' ,(1+1)*2) #​答案: 4 復合型態的運算子 指定運算子 = 若是結合算術