1. 程式人生 > 其它 >181. 差分陣列學習

181. 差分陣列學習

1.查分陣列

1.首先名字看起來很高大上其實呢就是前一項減後一項, 不用怕
舉個例子: 
list1 = [2, 5, 4, 9, 7, 10, 0]
list1 = [0, 2, 5, 4, 9, 7, 10, 0]  # 最前面補一個零(因為第一項沒有前一個元素)
diff_list = []
for i in range(1, len(list1)):
    diff_list.append(list1[i] - list1[i-1])  # 前一項減去後一項
print(diff_list)  
# 結果就是這個樣子, 他能幹嘛呢? 發現沒有如果給diff_list計算字首和剛好就是原陣列
diff_list = [2, 3, -1, 5, -2, 3, -10]

2.計算字首和(可能你不相信我說字首和就是他的原陣列沒關係,算一遍)
size = len(diff_list)
list2 = [0 for _ in range(size +1)]
for i in range(1, size + 1):  # 這裡是為了計算字首和陣列
    list2[i] = list2[i-1] + diff_list[i-1]
print(list2)
[0, 2, 5, 4, 9, 7, 10, 0]  你看看他想不想list1也就是原陣列
這個時候你明白了差分陣列的其中一個作用了把?計算字首和還原陣列

3.產品聽需求了,我們需要給
	1. [1, 4]的數值全部加上3
    2. 上面條件的基礎上[3, 5] 減去5
是不是感覺很簡單? 遍歷一遍加上去就可以了,但是如果如果數量級比較大1e5你1000ms可以過去麼? 很不幸我在力扣裡面超時了.

這時候就需要利用差分陣列的性質了: 將原始陣列中元素同時加上或者減掉某個數,那麼他們的差分陣列其實是不會變化的
沒事不懂咋就舉例子: 
list1 =     [0, 2, 5, 4, 9, 7, 10, 0]  原陣列
diff_list = [2, 3, -1, 5, -2, 3, -10]  差分陣列

[1, 4]的數值全部加上3
如果我們給差分陣列1索引位置元素+3, 4+1=5所以位置-3會造成什麼?
diff_list = [2, 3+3, -1, 5, -2, 3-3, -10]

# 說話你們不信, 直接看程式碼, 結果[0, 2, 8, 7, 12, 10, 10, 0], 看到了什麼[1,4]+3了, 其他資料沒影響是不是很完美.(0是我們加的輔助數字不需要管)
diff_list = [2, 3+3, -1, 5, -2, 3-3, -10]
size = len(diff_list)
list2 = [0 for _ in range(size +1)]
for i in range(1, size + 1):  # 這裡是為了計算字首和陣列
    list2[i] = list2[i-1] + diff_list[i-1]
print(list2)  # [0, 2, 8, 7, 12, 10, 10, 0]

上面條件的基礎上[3, 5] 減去5 # 經過上面我相信你已經明白了,如果需要修改[x,y]位置元素大小隻需要給x位置+對應數字, y+1位置-對應陣列即可(相信減法你可以理解),進行第二個條件
diff_list = [2, 3+3, -1, 5-5, -2, 3-3, -10+5]
size = len(diff_list)
list2 = [0 for _ in range(size +1)]
for i in range(1, size + 1):  # 這裡是為了計算字首和陣列
    list2[i] = list2[i-1] + diff_list[i-1]
print(list2)  # [0, 2, 8, 7, 12, 10, 10, 0]
[0, 2, 8, 7, 12, 10, 10, 0]  # 條件1結果
[0, 2, 8, 7, 7, 5, 5, 0]  # 條件2結果

# 防止你們不相信, 我暴力的修改也給出來, 如下
list1 = [2, 5, 4, 9, 7, 10, 0]
size = len(list1)
for i in range(size):
    if 1 <= i <= 4:
        list1[i] += 3

    if 3 <= i <= 5:
        list1[i] -= 5
print(list1)   # [2, 8, 7, 7, 5, 5, 0]


4.總結3寫成程式碼diff_list差分陣列  [x, y]位置加上同樣大小的數m
diff[x] += m
diff[y+1] -= 1 # y+1需要小於陣列長度n, len(diff_list)
注意 只能是區間元素同時增加或減少相同的數的情況才能用

5.實踐開始,

1.題目1: HDU-1556 Color the Ball

說實話第一次遇到查分陣列相關問這個氣球搞得我很懵逼, 但是看了大佬的程式碼一下在就明白了?
我把這題根據力扣的題目改了一下:(還是返回氣球總共修改了幾次)
其中n表示氣球數量, balls陣列放置每次塗改顏色的區間(前後都包含)給你看個例子就好了
例1:
n = 3
balls = [[1, 1], [2,3], [3,3]]
結果 [1, 1, 1]
例2:
n = 3
balls = [[1, 1], [1,2], [1,3]]
結果 [3, 2, 1]  # 這個結果其實就是最後的差分陣列,他記錄了每個位置對應的氣球修改的次數
程式碼如下:
def func(balls, n):
        a = [0 for _ in range(n+1)]  # 結果陣列
        b = [0 for _ in range(n+1)]  # 差分陣列

        for i in range(len(balls)):
            x, y = balls[i]
            b[x] += 1  # 1其實就是每次修改一遍
            if y < n:
                b[y+1] -= 1

        for i in range(1, n+1):
            a[i] = a[i-1] + b[i]  # 字首和

        return a[1:]

1.題目二: 1109. 航班預訂統計

這個題很題目一很類似, 上面統計修改次數, 這個題目統計座位數目. 只不過給區間加上了權重,也就是座位數
class Solution(object):
    def corpFlightBookings(self, bookings, n):
        """
        https://blog.csdn.net/qq_44786250/article/details/100056975  參考這個學習查分陣列
        航班編號        1   2   3   4   5
        預訂記錄 1 :   10  10
        預訂記錄 2 :       20  20
        預訂記錄 3 :       25  25  25  25
        總座位數:      10  55  45  25  25
        :type bookings: List[List[int]]
        :type n: int
        :rtype: List[int]
        """
        a = [0 for _ in range(n+1)]
        b = [0 for _ in range(n+1)]

        for i in range(len(bookings)):
            x, y, w = bookings[i]
            b[x] += w  # 同樣的程式碼加上權重就好了
            if y < n:
                b[y+1] -= w

        for i in range(1, n+1):
            a[i] = a[i-1] + b[i]

        return a[1:]