➕用Python來實現 Prefix sum 前綴和

➕用Python來實現 Prefix sum 前綴和

更新於 發佈於 閱讀時間約 1 分鐘

定義

Prefix Sum(前綴和)是一種用於計算陣列中任意區間和的高效方法

前綴和算是一種犧牲空間換取時間效能提升的策略。
這在需要頻繁查詢區間和的情況下特別有用。


一開始,初始化時花費O(n)時間,掃描每個元素累加,建立一個prefix sum table
接著,提供query介面,提供使用者查詢任意的區間和,並且能夠在O(1)得到答案


示意圖

raw-image

優點

1.提升區間和查詢效能,可以在O(1)時間內計算並且得到任意區間和。


缺點

1.需要額外花費O(n)空間來建立prefix sum table。

2.事前需要花費O(n)時間掃描每個陣列元素累加,建立prefix sum table。


Prefix Sum的class定義 與 初始化

class PrefixSum:
def __init__(self, arr):

# 建構子
self.prefix_sums = self._compute_prefix_sums(arr)

def _compute_prefix_sums(self, arr):

# 事先花費O(n)時間計算前綴和
prefix_sums = [0 for _ in range(len(arr)) ]

prefix_sums[0] = arr[0]

for i in range(1, len(arr)):
prefix_sums[i] = prefix_sums[i - 1] + arr[i]

return prefix_sums

Prefix Sum常見的操作


1.查詢區間和 range_sum(left, right)


如果left 是零,代表左邊端點是起點,直接返回self.prefix_sums[right]即可。

如果left非零,利用區間和抵銷的觀念,計算

self.prefix_sums[right] - self.prefix_sums[left-1] 得到區間和。


時間複雜度: O(1)

    def range_sum(self, left, right):

if left == 0:
return self.prefix_sums[right]

else:
return self.prefix_sums[right] - self.prefix_sums[left-1]

測試範例

raw-image

完整的Prefix sum實作和程式碼

class PrefixSum:
def __init__(self, arr):
self.prefix_sums = self._compute_prefix_sums(arr)

def _compute_prefix_sums(self, arr):
prefix_sums = [0 for _ in range(len(arr)) ]

prefix_sums[0] = arr[0]

for i in range(1, len(arr)):
prefix_sums[i] = prefix_sums[i - 1] + arr[i]

return prefix_sums

def range_sum(self, left, right):

if left == 0:
return self.prefix_sums[right]

else:
return self.prefix_sums[right] - self.prefix_sums[left-1]

def test():
# Demo
arr = [3, 4, 1, 7, 9, 1]
prefix_sum = PrefixSum(arr)
print("Input array :", arr)
print("Prefix sum :", prefix_sum.prefix_sums)
print("\nSum of range (1, 3):", prefix_sum.range_sum(1, 3))
print("Sum of range (0, 5):", prefix_sum.range_sum(0, 5))


if __name__ == '__main__':
test()

測試輸出

Input array : [3, 4, 1, 7, 9, 1]
Prefix sum : [3, 7, 8, 15, 24, 25]

Sum of range (1, 3): 12
Sum of range (0, 5): 25

結語


其實前綴和就是陣列元素的累加,而區間和就是區間元素的累加
透過事前額外的計算建表,提升run-time 區間和的查詢與計算效能


讀者可以透過紙筆追蹤演算法和程式執行邏輯,測試幾個簡單的小範例,

會有更深刻的了解和體會!


Prefix sum相關的演算法練習題與詳解


前綴和應用: 指定目標值的子陣列數目 Binary Subarrays With Sum_Leetcode #930


前綴和應用: 總和=k的子陣列有幾個 Subarray Sum Equals K_Leetcode #560


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


前綴和應用: 尋找旅途中的海拔最高點_Leetcode #1732 精選75題解析

avatar-img
小松鼠的演算法樂園
95會員
426內容數
由有業界實戰經驗的演算法工程師, 手把手教你建立解題的框架, 一步步寫出高效、清晰易懂的解題答案。 著重在讓讀者啟發思考、理解演算法,熟悉常見的演算法模板。 深入淺出地介紹題目背後所使用的演算法意義,融會貫通演算法與資料結構的應用。 在幾個經典的題目融入一道題目的多種解法,或者同一招解不同的題目,擴展廣度,並加深印象。
留言
avatar-img
留言分享你的想法!
從Python 內建deque資料結構的角度切入, 同時了解deque 與 FIFO Queue相關的function用法。 collections.deque是一種兩端點皆可進出的雙端佇列 在兩端點高效地在O(1)常數時間內添加和刪除元素。 這使得deque非常適合實現FIFO Queue
井字遊戲(OOXX)的遊戲描述 Tic Tac Toe(井字遊戲)是經典的雙人棋盤遊戲,在一個3x3的方格中進行。 每回合兩個玩家輪流選一個位置,先讓自己的符號(是 X 或 O)在 水平線、垂直線或對角線上連成一線的玩家宣告獲勝。
深入探討圖(Graph)的基本概念 及 最短路徑Shortest Path的尋找。 我們專注於廣度優先搜尋(BFS)演算法,以等權圖的最短路徑為例, 詳細說明如何利用BFS從起點擴散到終點,並且提供詳細的程式碼範例。 透過實作,讀者能夠更清楚理解圖論及BFS的應用,並體會水波紋擴散模型的重要性。
從Python 內建deque資料結構的角度切入, 同時了解deque 與 FIFO Queue相關的function用法。 collections.deque是一種兩端點皆可進出的雙端佇列 在兩端點高效地在O(1)常數時間內添加和刪除元素。 這使得deque非常適合實現FIFO Queue
井字遊戲(OOXX)的遊戲描述 Tic Tac Toe(井字遊戲)是經典的雙人棋盤遊戲,在一個3x3的方格中進行。 每回合兩個玩家輪流選一個位置,先讓自己的符號(是 X 或 O)在 水平線、垂直線或對角線上連成一線的玩家宣告獲勝。
深入探討圖(Graph)的基本概念 及 最短路徑Shortest Path的尋找。 我們專注於廣度優先搜尋(BFS)演算法,以等權圖的最短路徑為例, 詳細說明如何利用BFS從起點擴散到終點,並且提供詳細的程式碼範例。 透過實作,讀者能夠更清楚理解圖論及BFS的應用,並體會水波紋擴散模型的重要性。