除自身以外數組的乘積-leetcode
題目描述
給你一個整數數組 nums,返回 數組 answer ,其中 answer[i] 等于 nums 中除 nums[i] 之外其余各元素的乘積 。
題目數據 保證 數組 nums之中任意元素的全部前綴元素和后綴的乘積都在 32 位 整數范圍內。
請 不要使用除法,且在 O(n) 時間復雜度內完成此題。
示例 1:
輸入: nums = [1,2,3,4]
輸出: [24,12,8,6]
示例 2:
輸入: nums = [-1,1,0,-3,3]
輸出: [0,0,9,0,0]
提示:
2 <= nums.length <= 105-30 <= nums[i] <= 30- 輸入 保證 數組
answer[i]在 32 位 整數范圍內
進階:你可以在 O(1) 的額外空間復雜度內完成這個題目嗎?( 出于對空間復雜度分析的目的,輸出數組 不被視為 額外空間。)
解法一
思路:
利用前綴乘積和后綴乘積的方法進行求解,例如L[i]為i的左側所有數乘積,R[i]為i的右側所有數乘積,那么對于answer[i]則為L[i-1]*R[i+1],同時L數組計算時間復雜度為O(n),從左向右遍歷,R數組也是同理。
代碼:
class Solution {
public int[] productExceptSelf(int[] nums) {
int numsLen=nums.length;
int[] res=new int[numsLen];
//前綴和后綴乘積
int[] prefix=new int[numsLen+2];
int[] suffix=new int[numsLen+2];
Arrays.fill(prefix,1);
Arrays.fill(suffix,1);
for(int i=1;i<=numsLen;i++){
suffix[i]=nums[i-1]*suffix[i-1];
}
for(int i=numsLen;i>0;i--){
prefix[i]=nums[i-1]*prefix[i+1];
}
for(int i=1;i<=numsLen;i++){
res[i-1]=prefix[i+1]*suffix[i-1];
}
return res;
}
}
解法二
思路:
來自官方解答。盡管上面的方法已經能夠很好的解決這個問題,但是空間復雜度并不為常數。
由于輸出數組不算在空間復雜度內,那么我們可以將 L 或 R 數組用輸出數組來計算。先把輸出數組當作 L 數組來計算,然后再動態構造 R 數組得到結果。讓我們來看看基于這個思想的算法。
步驟:
- 初始化 answer 數組,對于給定索引 i,answer[i] 代表的是 i 左側所有數字的乘積。
- 構造方式與之前相同,只是我們試圖節省空間,先把 answer 作為方法一的 L 數組。
- 這種方法的唯一變化就是我們沒有構造 R 數組。而是用一個遍歷來跟蹤右邊元素的乘積。并更新數組 answer[i]=answer[i]?R。然后 R 更新為 R=R?nums[i],其中變量 R 表示的就是索引右側數字的乘積
代碼:
class Solution {
public int[] productExceptSelf(int[] nums) {
int length = nums.length;
int[] answer = new int[length];
// answer[i] 表示索引 i 左側所有元素的乘積
// 因為索引為 '0' 的元素左側沒有元素, 所以 answer[0] = 1
answer[0] = 1;
for (int i = 1; i < length; i++) {
answer[i] = nums[i - 1] * answer[i - 1];
}
// R 為右側所有元素的乘積
// 剛開始右邊沒有元素,所以 R = 1
int R = 1;
for (int i = length - 1; i >= 0; i--) {
// 對于索引 i,左邊的乘積為 answer[i],右邊的乘積為 R
answer[i] = answer[i] * R;
// R 需要包含右邊所有的乘積,所以計算下一個結果時需要將當前值乘到 R 上
R *= nums[i];
}
return answer;
}
}

浙公網安備 33010602011771號