题目描述:
给定一个数组 A[0, 1, 2, 3, ... , n-1]
请构建一个数组 B[0, 1, 2, 3, ... , n-1]
条件为 B[i] = A[0]*A[1]*A[2]*...*A[i-1]*A[i+1]*...*A[n-1]
限制: 不能使用除法 !
也就是说 B[i]
等于 A 数组中除 A[i]
以外的其他所有元素之积
思路1:
先来举例分析一下
例如数组A = {4, 7, 2, 5, 9}
, 元素个数n = 5
B[0] = 1*7*2*5*9
B[1] = 4*1*2*5*9
B[2] = 4*7*1*5*9
…
我们发现相当于把A[i]
变成了 1
题目说除A[i]
以外所有元素的乘积, 那么把A[i]
变成1
, 也就相当于没有乘以A[i]
所以我们可以在每次乘之前, 把A[i]
变成1
, 但是为了后面恢复, 不然后面数组A都成了1
, 所以要用临时变量保存A[i]
实现代码:
class Solution
{
public:
vector<int> multiply(vector<int> &A)
{
//int A[] = {4, 7, 2, 5, 9};
int size = A.size();
vector<int> B(size);
int i = 0;
for(i = 0; i < size; i++)
{
int temp = A[i];
A[i] = 1;
B[i] = 1;
int j = 0;
for(j = 0; j < size; j++)
{
//printf("A[%d] = %d\n", j, A[j]);
B[i] = B[i] * A[j];
}
A[i] = temp;
//printf("B[%d] = %d\n", i, B[i]);
}
return B;
}
};
但是这种方法的时间复杂度为 O(N^2)
, 并且需要改动数组A, 虽然之后复原了, 但仍有可能出现问题. 为了提高效率和安全性, 再想另一种方法.
思路2:
题目说除A[i]
以外所有元素的乘积, 所以可以把A[i]当作一个分界线, 把乘积分为两部分
A[0]*A[1]*A[2]*...*A[i-1]
和 A[i+1]*...*A[n-1]
先算出前一部分的乘积, 再乘以后一部分的乘积.
class Solution
{
public:
vector<int> multiply(const vector<int> &A)
{
//int A[] = {4, 7, 2, 5, 9};
int size = A.size();
vector<int> B(size);
int i = 0;
B[0] = 1;
for(i = 1; i < size; i++)
{
B[i] = B[i-1] * A[i-1];
}
int temp = 1;
for(i = size - 2; i >= 0; i--)
{
temp = temp * A[i+1];
B[i] = B[i] * temp;
}
return B;
}
};
这样的时间复杂度为 O(N)
, 而且不会改变数组 A 的值.