合縱連橫: 從區間和應用理解 前綴和 的本質

小松鼠-avatar-img
發佈於演算法題目解析 個房間
更新於 發佈於 閱讀時間約 10 分鐘


這篇文章,會帶著大家複習以前學過的前綴和框架

並且以區間和的概念與應用為核心,

貫穿一些相關聯的題目,透過框架複現來幫助讀者理解這個演算法框架。


前綴和 prefix sum框架 與 區間和計算的關係式

raw-image

詳細的推導過程可參考這部教學影片


接下來,我們會用這個上面這種框架,貫穿一些同類型,有關聯的題目
(請讀者、或觀眾留意上面的這種 前綴和 框架,之後的解說會反覆出現)

Range Sum Query - Immutable 一維的區間和

基本上就是前綴和框架的標準應用,直接使用推導出來的區間和關係式即可。


由前綴和快速計算一維的區間和

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, i: int, j: int) -> int:


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

好,接下來看一個推廣應用

Find Pivot Index 尋找左右平衡的軸心點

題目要求我們找出index i 使得 A[0] + ... A[i-1] = A[i+1] + ... + A[n]

也就是左右平衡的軸心點位置。

等價於 A[0, i-1] 的區間和 = A[i+1, n]的區間和

既然我們已經知道任意給定區間的區間和快速計算方式,那這邊也是同樣道理。

建立前綴和表格,接著用前綴和表格查表計算左區間和 與 右區間的和
當兩者相等時,當下的index i 就是平衡軸心點


由前綴和快速計算兩個一維的區間和

class Solution:
def pivotIndex(self, nums: List[int]) -> int:

# s = prefix sum of array
# s[i] = nums[0] + nums[1] + ... + nums[i]
s = list( itertools.accumulate(nums) )
total_sum = sum( nums )

# Linear scan on each index
for i in range( len(nums) ):

left_sum = s[i-1] if i >= 1 else 0
right_sum = total_sum - s[i]

# Find pivot index from definition
if left_sum == right_sum:
return i

return -1

再來看一個進階應用。

Subarray sum Equals k

題目問有多少個子陣列,他們的區間和恰好=k。

那這題就會用到之前學會的技巧,用前綴和去高速計算區間和

並且額外運用一個觀念:
如果前綴和S,與S+k都曾經出現過,代表必定存在某個區間,他們的區間和恰好為k

還有另一個等價的說法,

如果前綴和S,與S - k都曾經出現過,代表必定存在某個區間,他們的區間和恰好為k

範例與示意圖:

image

image


搭配字典與前綴和的解題程式碼:

from collections import defaultdict

class Solution:
def subarraySum(self, nums: List[int], k: int) -> int:

# prefix sum
cur_prefix_sum = 0

# counter of subarray with sum = k
counter = 0

# key: subarray prefix sum
# value: occurrence of given prefix sum
prefixSum_map = defaultdict(int)

# prefix summation 0 is reached by selecting nothing
prefixSum_map[0] = 1

for number in nums:

# update prefix sum from first element to current position
cur_prefix_sum += number

# if curPrefixSum - k exist in map, then sub array with sum = k must exist in somewhere
if (cur_prefix_sum - k) in prefixSum_map:
counter += prefixSum_map[cur_prefix_sum - k]

# update occurrence of curPrefixSum
prefixSum_map[cur_prefix_sum] += 1

return counter

同樣的觀念推廣到二維區間和的計算,也是可以的唷!

raw-image


給個具體的例子幫助理解 (下圖來自wiki)

image

image

對應的例題就是

Range Sum Query 2D - Immutable 二維的區間和

類似的操作,一樣是先建立前綴和表格,接著查表快速計算指定範圍的二維區間和。

class NumMatrix:

def __init__(self, matrix: List[List[int]]):

if not matrix:
# Reject empty matrix
return

# get height and width of matrix (also known as image)
h, w = len(matrix), len(matrix[0])

# build integral image by recurrence relationship
self.integral_image = [ [ 0 for _ in range(w) ] for _ in range(h) ]

for y in range(h):

summation = 0

for x in range(w):

summation += matrix[y][x]
self.integral_image[y][x] = summation

if y > 0:
self.integral_image[y][x] += self.integral_image[y-1][x]

return

def sumRegion(self, row1: int, col1: int, row2: int, col2: int) -> int:

bottom_right = self.integral_image[row2][col2]
bottom_left = self.integral_image[row2][col1-1] if col1 >= 1 else 0
top_right = self.integral_image[row1-1][col2] if row1 >= 1 else 0
top_left = self.integral_image[row1-1][col1-1] if col1 >= 1 and row1 >=1 else 0

return bottom_right - bottom_left - top_right + top_left


結語

好,今天一口氣介紹了最精華的部分,

通用的前綴和框架,還有相關的區間和衍伸題與演算法建造,


希望能幫助讀者、觀眾徹底理解它的原理,

並且能夠舉一反三,洞察其背後的本質和了解相關的應用領域!


感謝收看囉! 我們下篇文章再見~

留言
avatar-img
留言分享你的想法!
小松鼠-avatar-img
發文者
2024/09/02
➕用Python來實現 Prefix sum 前綴和提及了這篇文章,趕快過去看看吧!
小松鼠-avatar-img
發文者
2024/05/29
avatar-img
小松鼠的演算法樂園
96會員
427內容數
由有業界實戰經驗的演算法工程師, 手把手教你建立解題的框架, 一步步寫出高效、清晰易懂的解題答案。 著重在讓讀者啟發思考、理解演算法,熟悉常見的演算法模板。 深入淺出地介紹題目背後所使用的演算法意義,融會貫通演算法與資料結構的應用。 在幾個經典的題目融入一道題目的多種解法,或者同一招解不同的題目,擴展廣度,並加深印象。
2024/09/13
給定一個整數陣列arr,和一串區間XOR請求queries。 請計算queries所請求的區間XOR值,並且以陣列的形式返回答案。
Thumbnail
2024/09/13
給定一個整數陣列arr,和一串區間XOR請求queries。 請計算queries所請求的區間XOR值,並且以陣列的形式返回答案。
Thumbnail
2024/08/27
Path with Maximum Probability 題目給定一個無向圖(雙向移動皆可), 提供每條邊的起終點,和每條邊對應的通過時的成功機率。 請問從起點start走到終點end的最高成功機率是多少? 如果完全沒有路徑可以抵達,則返回0。
Thumbnail
2024/08/27
Path with Maximum Probability 題目給定一個無向圖(雙向移動皆可), 提供每條邊的起終點,和每條邊對應的通過時的成功機率。 請問從起點start走到終點end的最高成功機率是多少? 如果完全沒有路徑可以抵達,則返回0。
Thumbnail
2024/08/21
題目敘述 664. Strange Printer 有一台奇怪的印表機, 每次操作只能連續印同樣的字母,但是列印的長度可以自由控制。 而且,印刷的時候,可以蓋過去舊的字元。 (這邊當然不合常理,讀者可以理解成塗了立可帶再蓋過去的情境) 給定一個輸入字串s,請問最少需要幾次操作,才能印出字串s?
Thumbnail
2024/08/21
題目敘述 664. Strange Printer 有一台奇怪的印表機, 每次操作只能連續印同樣的字母,但是列印的長度可以自由控制。 而且,印刷的時候,可以蓋過去舊的字元。 (這邊當然不合常理,讀者可以理解成塗了立可帶再蓋過去的情境) 給定一個輸入字串s,請問最少需要幾次操作,才能印出字串s?
Thumbnail
看更多
你可能也想看
Thumbnail
1.0 從函數到函算語法 1.4 函算語法 1.4.1 語法範疇理論導論 1.4.2 函算語法與函數概念 四 在以語構範疇為單位的語言結構上,同樣可以應用前述的函數概念或規則。其中一個最大的分別是,若以 1.4.2_4 為用作對比的例子,函算語法的論域 (domain of dis
Thumbnail
1.0 從函數到函算語法 1.4 函算語法 1.4.1 語法範疇理論導論 1.4.2 函算語法與函數概念 四 在以語構範疇為單位的語言結構上,同樣可以應用前述的函數概念或規則。其中一個最大的分別是,若以 1.4.2_4 為用作對比的例子,函算語法的論域 (domain of dis
Thumbnail
1.0 從函數到函算語法 1.4 函算語法 1.4.1 語法範疇理論導論 1.4.2 函算語法與函數概念 三 弗雷格從語言結構的觀點出發,提出了函數可以被視為一個不完整的表式。如果我們將一個函數拆解為一個由一個函子及其 (一個或多個) 論元所組成的表式,那麼該函子便是一個有待滿足的
Thumbnail
1.0 從函數到函算語法 1.4 函算語法 1.4.1 語法範疇理論導論 1.4.2 函算語法與函數概念 三 弗雷格從語言結構的觀點出發,提出了函數可以被視為一個不完整的表式。如果我們將一個函數拆解為一個由一個函子及其 (一個或多個) 論元所組成的表式,那麼該函子便是一個有待滿足的
Thumbnail
1.0 從函數到函算語法 1.4 函算語法 1.4.1 語法範疇理論導論 1.4.2 函算語法與函數概念 二 關於函數的演變和弗雷格對函數的看法,前面的 1.2 節和 1.3 節已經談論了不少。 由於函數在數學﹑邏輯學﹑計算語言學極為重要,更且是本書闡述的語法的中心概念,因此有必要再略作
Thumbnail
1.0 從函數到函算語法 1.4 函算語法 1.4.1 語法範疇理論導論 1.4.2 函算語法與函數概念 二 關於函數的演變和弗雷格對函數的看法,前面的 1.2 節和 1.3 節已經談論了不少。 由於函數在數學﹑邏輯學﹑計算語言學極為重要,更且是本書闡述的語法的中心概念,因此有必要再略作
Thumbnail
1.0 從函數到函算語法 1.4 函算語法 1.4.1 語法範疇理論導論 九 為能清晰說明,我們給範疇次序標號 (即置頂的 1-5),使整個推導過程看似一個矩陣﹕ 1.4.1_5.3 艾杜凱維茨的推導矩陣 第 2 行的 gr:1 (C1, C2) 是說 gr 用於第 1 行的 C
Thumbnail
1.0 從函數到函算語法 1.4 函算語法 1.4.1 語法範疇理論導論 九 為能清晰說明,我們給範疇次序標號 (即置頂的 1-5),使整個推導過程看似一個矩陣﹕ 1.4.1_5.3 艾杜凱維茨的推導矩陣 第 2 行的 gr:1 (C1, C2) 是說 gr 用於第 1 行的 C
Thumbnail
1.0 從函數到函算語法 1.4 函算語法 1.4.1 語法範疇理論導論 五 艾杜凱維茨的語構範疇理論有兩個關於形式語言的預設﹕[Ajdukiewicz 1935: 2]57 1.4.1_1 一個詞構 (das Wortgefüge)58 必須是一個連貫的整體才具有意義。 1.
Thumbnail
1.0 從函數到函算語法 1.4 函算語法 1.4.1 語法範疇理論導論 五 艾杜凱維茨的語構範疇理論有兩個關於形式語言的預設﹕[Ajdukiewicz 1935: 2]57 1.4.1_1 一個詞構 (das Wortgefüge)58 必須是一個連貫的整體才具有意義。 1.
Thumbnail
1.0 從函數到函算語法 1.1 句子成份 本書關注的是句子成份的分析。 如前述,詞類和句子成份是兩個很不一樣的概念。 詞類的劃分屬歸類性的描述。我們先有一個給定的詞彙,然後劃分若干詞類,比如名詞﹑動詞﹑形容詞等,再進而對詞彙中的每一個詞進行分類,即說某詞屬名詞﹑某詞屬動詞﹑某詞可以是名
Thumbnail
1.0 從函數到函算語法 1.1 句子成份 本書關注的是句子成份的分析。 如前述,詞類和句子成份是兩個很不一樣的概念。 詞類的劃分屬歸類性的描述。我們先有一個給定的詞彙,然後劃分若干詞類,比如名詞﹑動詞﹑形容詞等,再進而對詞彙中的每一個詞進行分類,即說某詞屬名詞﹑某詞屬動詞﹑某詞可以是名
Thumbnail
1.0 從函數到函算語法 1.1 句子成份 一 語言學的一個分支是對語法的研究,語法的一個分支是對語構 (syntax) 的研究。研究語法的一個方法始於對一個語言的詞彙集裡的成員進行分類,也就是以詞類或詞彙範疇為研究的對象。9 因此如何分類或應該按什麼原則分類似乎是一個重要議題,但傳統語法學
Thumbnail
1.0 從函數到函算語法 1.1 句子成份 一 語言學的一個分支是對語法的研究,語法的一個分支是對語構 (syntax) 的研究。研究語法的一個方法始於對一個語言的詞彙集裡的成員進行分類,也就是以詞類或詞彙範疇為研究的對象。9 因此如何分類或應該按什麼原則分類似乎是一個重要議題,但傳統語法學
Thumbnail
目錄 序 導論: 一個西方觀點的評述 1.0 從函數到函數算法 ......1.1 句子成份
Thumbnail
目錄 序 導論: 一個西方觀點的評述 1.0 從函數到函數算法 ......1.1 句子成份
追蹤感興趣的內容從 Google News 追蹤更多 vocus 的最新精選內容追蹤 Google News