算法③:構建乘積數組
題目鏈接:https://leetcode-cn.com/problems/gou-jian-cheng-ji-shu-zu-lcof/
題目要求:
給定一個數組 A[0,1,…,n-1],請構建一個數組 B[0,1,…,n-1],其中 B 中的元素 B[i]=A[0]×A[1]×…×A[i-1]×A[i+1]×…×A[n-1]。不能使用除法。
示例 1:
輸入: [1,2,3,4,5]
輸出: [120,60,40,30,24]
提示:
所有元素乘積之和不會溢出 32 位整數
a.length <= 100000
解題思路
思路一
本題的難點在於 不能使用除法 ,即需要 只用乘法 生成數組 BB 。
根據題目對 B[i]B[i] 的定義,可列表格,如下圖所示:
根據表格的主對角線(全爲 11 ),可將表格分爲 上三角 和 下三角 兩部分。分別迭代計算下三角和上三角兩部分的乘積,即可 不使用除法 就獲得結果。
算法流程:
初始化:數組 BB ,其中 B[0] = 1B[0]=1 ;輔助變量 tmp = 1tmp=1 ;
計算 B[i]B[i] 的 下三角 各元素的乘積,直接乘入 B[i]B[i] ;
計算 B[i]B[i] 的 上三角 各元素的乘積,記爲 tmptmp ,並乘入 B[i]B[i] ;
返回 BB 。
複雜度分析:
時間複雜度 O(N)O(N) : 其中 NN 爲數組長度,兩輪遍歷數組 aa ,使用 O(N)O(N) 時間。
空間複雜度 O(1)O(1) : 變量 tmptmp 使用常數大小額外空間(數組 bb 作爲返回值,不計入複雜度考慮)
參考動圖算法解析:
https://leetcode-cn.com/problems/gou-jian-cheng-ji-shu-zu-lcof/solution/mian-shi-ti-66-gou-jian-cheng-ji-shu-zu-biao-ge-fe/
思路二
對稱遍歷!
建立兩個數組:C[n]和D[n]
第一個存放左半部分的值,第二個存放右半部分的值;
因爲b的值是把a數組拆成了左右兩部分,最後乘積得到的
C[i]表示a數組從第0項乘到i-1項的乘積;
D[i]表示從i+1到n-1項的乘積;兩項相乘,就是對B[i]
圖解!變成
找規律:
c[n]=c[n-1]*a[n-1]
d[n]=d[n+1]a[n+1],
也就是上一次結果a的值,然後兩個值相乘,得到b[n]
從上述想法優化:b數組本身可以代表左側數組c
再用temp變量記錄右側的值,沒算出一個值,就和左側的相乘,也就省去了右側的數組
class Solution {
public int[] constructArr(int[] a) {
if(0==a.length) {
return new int[0];
}
int length=a.length;
int[] b=new int[length];
b[0]=1;
for(int i=1;i<length;i++) {
b[i]=b[i-1]*a[i-1];
}
int temp=1;
for(int j=length-2;j>=0;j--) {
temp*=a[j+1];
b[j]*=temp;
}
return b;
}
}
java解法
class Solution {
public int[] constructArr(int[] a) {
int[] res = new int[a.length];
for (int i = 0, cur = 1; i < a.length; i++) {
res[i] = cur; // 先乘左邊的數(不包括自己)
cur *= a[i];
}
for (int i = a.length - 1, cur = 1; i >= 0; i--) {
res[i] *= cur; // 再乘右邊的數(不包括自己)
cur *= a[i];
}
return res;
}
}
C++解法
class Solution {
public:
vector<int> constructArr(const vector<int>& A) {
int n = A.size();
vector <int> b(n);
int temp = 1;
for (int i = 0; i < n; i++){
b[i] = temp;//如果要累乘的話需要把內容初始化爲1
temp *= A[i];//這樣先賦值,在對i進行累乘,可以使a[i]不被乘進去
//把所有左邊的都乘進數組裏了,用temp不重複計算!!利用上次的值!!
}
temp = 1; //重新清零
for (int i = n - 1;i >= 0; --i){
b[i] *= temp;//之前b[]還是個半成品
temp *= A[i];
}
return b;
}
};
C語言解法
int* constructArr(int* a, int aSize, int* returnSize){
int *arr = NULL;
int i, temp;
if (a == NULL || aSize <= 1) {
*returnSize = 0;
return a;
}
*returnSize = aSize;
arr = (int *)malloc(sizeof(int) * aSize);
arr[0] = 1;
for (i = 1; i < aSize; i++) {
arr[i] = arr[i - 1] * a[i - 1];
}
temp = 1;
for (i = aSize - 2; i >= 0; i--) {
temp *= a[i + 1];
arr[i] *= temp;
}
return arr;
}
Python解法
class Solution:
def constructArr(self, a: List[int]) -> List[int]:
n = len(a)
L, R = [1] * n, [1] * n
for i in range(1, n):
L[i] = L[i - 1] * a[i - 1]
for j in reversed(range(n - 1)):
R[j] = R[j + 1] * a[j + 1]
for i in range(n):
L[i] = L[i] * R[i]
return L