【LeetCode】Product of Array Except Self – 拿空間換時間 – 陣列、前綴和

tags: leetcode

https://leetcode.com/problems/product-of-array-except-self/description/

題目 LeetCode 238

思路

  1. 我們要把除了 nums[i] 以外的數乘起來,並且對每個 i 都做一次這件事情
  2. 最直覺的方法:阿就做阿,每個 i 都做一次嘛,沒什麼大不了
  3. 哭阿,在題目就講了要 $O(n)$,如果用這個方法會是 $O(n^2)$
  4. 我先把整個nums乘起來,然後再分別除以 nums[i]就好了,這樣就 $O(n)$ 了
  5. 可是這樣會有兩個疑慮: (1) 如果 nums[i] 是 0 怎麼辦 (2) 哭阿,題目又講了不能用除法…走頭無路了
  6. 重新思考一下這個題目,其實有很多乘法會重複做,比如說如果
    $$nums = [a, b, c, d]$$
    那 output會是:
    $$[b\times c \times d, a\times c \times d, a\times b \times d, a\times b \times c]$$
  7. 既然速度要快,那我們就 拿空間換取時間 ,來到本題的核心精神: 想辦法把會重複計算到的東西都存下來,要用的時候再拿出來就好,不要再重複計算一次
  8. 撞破可愛的小腦袋後,我們可以發現一個事實:對每個數字而言,都可以分成左翼和右翼 (比如對b而言,左翼是 [a], 右翼是 [c, d]),而每個位置要放的數字都是
    $$左翼 \times 右翼$$
  9. 所以我們可以把 全部可能的左翼乘積全部可能的右翼乘積 都存起來,像下圖
  1. 上面那步很難想啦…想不到就算了,這樣對每個 i 而言,只要把 l2r[i-1]r2l[i+1]乘起來就好了
  2. 我們可以寫出解法一

解法一

class Solution:
    def productExceptSelf(self, nums: List[int]) -> List[int]:
        n = len(nums)
        l2r = [1 for _ in range(n)]
        r2l = [1 for _ in range(n)]

        cur_val = 1
        for i in range(n):
            cur_val *= nums[i]
            l2r[i] = cur_val

        cur_val = 1
        for i in range(n-1, -1, -1):
            cur_val *= nums[i]
            r2l[i] = cur_val

        result = [1 for _ in range(n)]
        for i in range(n):
            if i == 0:
                result[i] = r2l[i+1]
            elif i == n-1:
                result[i] = l2r[i-1]
            else:
                result[i] = l2r[i-1] * r2l[i+1]
        return result

筆記

  • 在寫這題的時候會用到 for i in range ... 的語法,很多人會疑惑到底該怎麼寫 n, n+1, n-1, …,這時只要切記一個口訣: 含頭不含尾! 含頭不含尾! 含頭不含尾!
l = ['g', 'r', 'a', 'n', 'd', 'm', 'a']
for i in range(1, 5):
    print(l[i])

# 含頭 = 1,不含尾 = 5
# 所以 i 會從 1 到 4 : 1, 2, 3, 4
# output:
# r
# a
# n
# d

同樣的

l = ['g', 'r', 'a', 'n', 'd', 'm', 'a']
print(l[1:5])

# 含頭 = 1,不含尾 = 5
# output:
# ['r', 'a', 'n', 'd']

如果把一個list從後面iterate回來,要這樣寫

l = ['g', 'r', 'a', 'n', 'd', 'm', 'a']
for i in range(len(l) - 1, -1, -1):
    print(l[i])
# 含頭: len(l) -1 所以是最後一個element
# 不含尾 = -1,所以最後一個數字會是 0,也就是第一個element
# output:
# a
# m
# d
# n
# a
# r
# g
  • 寫完後發現文章裡面沒有提到前綴和…之後再來介紹好了
  • HackMD筆記: https://hackmd.io/@ga642381/BJ_EOUwti

留言討論區