題目來源:力扣(LeetCode)https://leetcode-cn.com/problems/product-of-array-except-selfpython
給你一個長度爲 n 的整數數組 nums,其中 n > 1,返回輸出數組 output ,其中 output[i] 等於 nums 中除 nums[i] 以外其他各元素的乘積。數組
示例:bash
輸入: [1,2,3,4] 輸出: [24,12,8,6]
提示: 題目數據保證數組之中任意元素的所有前綴元素和後綴(甚至是整個數組)的乘積都在 32 位整數範圍內。spa
說明: 請不要使用除法,且在 O(n) 時間複雜度內完成此題。code
進階:blog
你能夠在常數空間複雜度內完成這個題目嗎?( 出於對空間複雜度分析的目的,輸出數組不被視爲額外空間。)索引
思路:左右乘積列表leetcode
先看題目的提示,保證數組中任意元素的所有前綴後綴(甚至整個數組)的乘積都在 32 位整數範圍內,那這裏就能夠不考慮數據溢出的問題。rem
再看說明,這個說明中表示,不可以使用除法。由於,若是要求除當前元素數組的乘積,只要先求得整個數組的乘積,除以當前元素,那麼就是要求的答案。(固然,這裏有個問題,若是當前元素是 0 的話,這裏就要注意。不過題目不建議往這個方向考慮解決的方法,那麼這裏就不展開去說明了。)get
如今看本篇幅使用的方法:左右乘積列表,這裏須要先構造 left,right 兩個數組,分別存儲當前元素左側的乘積以及右側的乘積。
具體的構造方法:
left
,right
。其中 left[i]
表示 i
左側所有元素的乘積。right[i]
表示 i
右側所有元素的乘積。開始填充數組。這裏須要注意 left[0]
和 right[lenght-1]
的值(length
表示數組長度,right
數組是從右側往左進行填充)。
left
數組而言,left[0]
表示原數組索引爲 0
的元素左側的全部元素乘積,這裏原數組第一位元素左側是沒有其餘元素的,因此這裏初始化爲 1
。而其餘的元素則爲:left[i] = left[i-1] * nums[i - 1]
right
數組,right[length-1]
表示原數組最末尾的元素右側全部元素的乘積。但由於最末尾右側沒有其餘元素,因此這裏 right[length-1]
也初始化爲 1
。其餘的元素則爲:right[i]=right[i+1]*nums[i+1]
output
數組,再次遍歷原數組,索引爲 i
的值則爲:output[i] = left[i] * right[i]
主要在於 left 和 right 數組的構造,具體的過程以下圖:
具體的實現代碼見【code 1】 部分。
上面的方法實現以後,時間複雜度爲 O(N),空間複雜度也是 O(N) (N 表示數組的長度)。由於 構造 left 和 right 數組,二者的數組長度就是 N。
題目中的進階部分,但願可以嘗試使用常數空間複雜度完成本題。(這裏不計輸出數組的空間)
方法仍是使用 左右乘積列表 的方法,可是這裏不在單獨構建 left 和 right 數組。直接在輸出數組中進行構造。
具體的思路:
left
數組進行構造right
數組計算結果具體的作法:
output
數組,先當成 left
數組進行構造,那麼 output[i]
就表示 i
左側全部元素的乘積。(具體的構造方法同上)output[i]
的值爲 output[i] * right
,同時更新 right
的值爲 right * nums[i]
表示遍歷下一個元素右側的元素乘積。具體實現代碼見【code 2】。
# code 1 class Solution: def productExceptSelf(self, nums: List[int]) -> List[int]: length = len(nums) left = [0] * length right = [0] * length output = [0] * length # 先填充 left 數組 # left 數組表示遍歷時 i 左側的乘積 # 由於數組第一個元素左側沒有其餘元素,因此 left 數組第一個元素爲 1 # left 數組接下來的元素則爲原數組的第一位元素與 left 數組第一位元素的乘積,依次類推 left[0] = 1 for i in range(1, length): left[i] = nums[i-1] * left[i-1] # 一樣的 right 數組從右往左進行填充 # 一樣數組末尾元素右側沒有其餘元素,因此末尾元素值爲 1 # 右邊往左的元素則爲原數組與 right 數組末尾往前一位元素的乘積,依次類推 right[length-1] = 1 for i in range(length-2, -1, -1): right[i] = nums[i+1] * right[i+1] # 從新遍歷,輸出 output 數組 # output[i] 等於 nums 中除 nums[i] 以外其他各元素的乘積 # 也就是 output[i] 的值爲 left[i] * right[i] for i in range(length): output[i] = left[i] * right[i] return output # code 2 class Solution: def productExceptSelf(self, nums: List[int]) -> List[int]: length = len(nums) output = [0] * length # 先構建 output 爲左側乘積列表 # 一樣初始化第一個元素爲 1 output[0] = 1 for i in range(1, length): output[i] = output[i-1] * nums[i-1] # 維護一個變量 right # 變量更新 output[i] 的值爲 output[i] * right # 同時更新 right = right * nums[i] 表示遍歷到下個元素右側的乘積(此時遍歷從右向左) # 初始化 right 爲 1 right = 1 for i in range(length-1, -1, -1): output[i] = output[i] * right right = right * nums[i] return output
【code 1 實現結果】
【code 2 實現結果】
肯定方法後,進行構建 left 和 right 數組。構造時須要注意的是 left[0]
和 right[length-1]
兩個元素。
left[0]
表示原數組索引爲 0 左側全部元素的乘積。而原數組索引爲 0 的元素左邊沒有元素,因此初始化爲 1。而其餘元素則爲:left[i] = left[i-1] * nums[i-1]
right[length-1]
表示原數組末尾元素右側全部乘積。這裏元素組最末尾的元素右側沒有其餘元素,因此 right[length-1]
也初始化爲 1。output
則爲:output[i] = left[i] * right[i]
output
的數組,更新值爲 output[i] * right
(注意:這裏遍歷時從右往左遍歷),更新 output
的值的同時,更新 right
的值爲 right * nums[i]
,這裏表示下一個遍歷的值右側全部元素的乘積。