題目
給定一個長度爲 n 的整數列表 nums,其中 n > 1,返回輸出列表 res ,其中 res[i] 等於 nums 中除 nums[i] 之外其餘各元素的乘積。
例如:
給定一個列表:[1, 2, 3, 4],返回結果:[24, 12, 8, 6]
注意:實現過程中,不允許使用 除法 ,且要求時間複雜度爲O(n)
實現思路
- 遍歷列表,對於遍歷到的當前元素,如果要計算出除其自身以外整數的乘積,我們只需要分別求出
左側所有元素的乘積
和右側所有元素的乘積
即可。假設給定列表爲:[1, 2, 3, 4],其具體計算過程如下:
第一個數 | 第二個數 | 第三個數 | 第四個數 | |
---|---|---|---|---|
給定列表的所有元素 | 1 | 2 | 3 | 4 |
當前元素左側部分的乘積 | 1 | 1 | 1 * 2 | 1 * 2 * 3 |
當前元素右側部分的乘積 | 2 * 3 * 4 | 3 * 4 | 4 | 1 |
左乘積 * 右乘積 | 1 * 2 * 3 * 4 | 1 * 3 * 4 | 1 * 2 * 4 | 1 * 2 * 3 * 1 |
計算最終結果 | 24 | 12 | 8 | 6 |
- 首先,正序遍歷,分別求出每個元素左側的所有元素的乘積,結果保存到 left_product_list
- 接着,倒序遍歷,分別求出每個元素右側的所有元素的乘積,結果保存到 right_product_list
- 最後,對每個遍歷到的元素,最終乘積結果 = 左乘積 * 右乘積,把結果保存到一個列表,最終返回即可
代碼實現
def productExceptSelf(nums):
res = []
left_product_list, right_product_list = [1], [1]
left_product, right_product = 1, 1
for i in range(1, len(nums)): # 從第一個元素開始,計算每個元素左側的所有元素的乘積
left_product *= nums[i - 1]
left_product_list.append(left_product)
for i in range(len(nums) - 2, -1, -1): # 從倒數第二個元素開始,計算每個元素右側的所有元素的乘積
right_product *= nums[i + 1]
right_product_list.append(right_product)
for i in range(len(nums)): # 注意 left_product_list 是正序計算,right_product_list 是倒序計算
left, right = left_product_list[i], right_product_list[len(nums) - 1 - i]
res.append(left * right)
return res
上面的實現方式中,我們專門定義了兩個列表:left_product_list、right_product_list,分別記錄左側元素乘積、右側元素乘積,這裏的空間複雜度是 O(n),如果我們不考慮返回列表空間的話,那麼其實可以針對上方代碼進行優化,讓其空間複雜度降到 常數級別 O(1):
def productExceptSelf(nums):
res = [1] * len(nums)
left_product, right_product = 1, 1
for i in range(1, len(nums)): # 從第一個元素開始,計算每個元素左側的所有元素的乘積
left_product *= nums[i - 1]
res[i] *= left_product
for i in range(len(nums) - 2, -1, -1): # 從倒數第二個元素開始,計算每個元素右側的所有元素的乘積
right_product *= nums[i + 1]
res[i] *= right_product
return res
上面的實現方式中,我們不再專門使用額外的列表來保存左右側元素乘積,而是將最終返回列表設置爲一個固定長度的列表,接着直接修改列表中的元素值,如此一來,如果不考慮返回列表空間的前提下,其空間複雜度就降到 O(1)。
從上面的代碼中,可以發現我們對列表進行了2次遍歷,第一次正序遍歷是爲了計算左乘積,第二次倒序遍歷是爲了計算右乘積,在這裏其實我們也可以繼續優化,僅通過一次遍歷來完成,最終優化後代碼如下:
def productExceptSelf(nums):
"""
針對 [1, 2, 3, 4] ,遍歷過程中,每個元素的左右累積均相乘
i=0, res[0]乘左累積,res[3]乘右累積;
i=1, res[1]乘左累積,res[2]乘右累積;
i=2, res[2]乘左累積,res[1]乘右累積;
i=3, res[3]乘左累積,res[0]乘右累積
"""
res = [1] * len(nums)
left_product, right_product = 1, 1
for i in range(len(nums)):
res[i] *= left_product
left_product *= nums[i] # 下標 i 位置元素的左側所有元素的累積
res[len(nums) - 1 - i] *= right_product
right_product *= nums[len(nums) - 1 - i] # 下標 len - 1 - i 位置元素的右側所有元素的累積
return res
更多Python編程題,等你來挑戰:Python編程題彙總(持續更新中……)