Given an array of n integers where n > 1, nums
, return an array output
such
that output[i]
is equal to the product of all the elements of nums
except nums[i]
.
Solve it without division and in O(n).
For example, given [1,2,3,4]
, return [24,12,8,6]
.
特殊情况
数组指针为空,数组长度为0,数组长度为1,代码中对这些情况,都直接返回传入的数组指针
数组成员包含整数0,非常重要的特殊条件
数组成员相乘以后的数值范围,是否会超出int范围
数组成员是否会有负数,这里正负没有影响,只是大小不要溢出了
测试用例
排除特殊情况以后,就没有什么特别的了,可以直接使用例题中的数据测试
解题思路
有多种解法
1. 暴力计算,时间复杂度O(n^2)效率太差。但是可以给出一些启发
2. 保留所有数相乘以后的总积,然后除以各个对应的数组成员即可,时间复杂度O(n)。 貌似很巧妙地解法,但是需要考虑总积溢出,数组成员为0的情况。例外情况的处理比较复杂。
3. 由于乘积不需要包含本项,所以可以使用两个数组,一个包含左侧乘积,另外一个包含右侧乘积,最后两者相乘取结果即可。空间复杂度O(n),时间复杂度O(n)。溢出的可能性稍微小一些,但是不需要考虑除零的问题了。代码比较直白,易懂。
4. 在3的基础上,先利用输出数组保留右侧乘积,再一边计算左侧乘积,一边覆盖输出数组。通过这样的改进,空间复杂度降为O(1)。输出数组不作为空间复杂度计算
C代码,方法3
int* poa(int* a, int n) {
if (a==NULL) return a;
if (n<=1) return a;
int* res = (int*)malloc(n * sizeof(int));
int* left = (int*)malloc(n * sizeof(int));
int* right = (int*)malloc(n * sizeof(int));
for (int i=0; i<n; i++) left[i] = right[i] = 1;
for (int i=1; i<n; i++) left[i] = left[i-1] * a[i-1];
for (int i=n-2; i>=0; i--) right[i] = right[i+1] * a[i+1];
for (int i=0; i<n; i++) res[i] = left[i] * right[i];
free(left);
free(right);
return res;
}
C++代码,方法3
void poa(int a[], int n, int out[]) {
if (a == NULL || n <= 1) return;
// assume out is always valid
int* left = new int[n];
int* right = new int[n];
for (int i=0; i<n; i++) left[i] = right[i] = 1;
for (int i=1; i<n; i++) left[i] = left[i-1] * a[i-1];
for (int i=n-2; i>=0; i--) right[i] = right[i+1] * a[i+1];
for (int i=0; i<n; i++) out[i] = left[i] * right[i];
delete[] left;
delete[] right;
}
C++代码,方法3,用向量
#include <iostream>
#include <vector>
using namespace std;
void poa(vector<int>& a, vector<int>& out) {
int n = a.size();
if (n < 1) return;
// a.size() == 1, return [1]
// assume out is always valid
vector<int> left(n, 1), right(n, 1); //注意是用圆括号初始化数组大小
for (int i=1; i<n; i++) left[i] = left[i-1] * a[i-1];
for (int i=n-2; i>=0; i--) right[i] = right[i+1] * a[i+1];
for (int i=0; i<n; i++) out[i] = left[i] * right[i];
}
int main(int argc, char * argv[])
{
int a[] = {3,4,2,5};
int n = sizeof(a)/sizeof(int);
vector<int> in(a, a+n);
vector<int> out(n);
poa(in, out);
for (int i=0; i<n; i++) cout << in[i] << " ";
cout << endl;
for (int i=0; i<n; i++) cout << out[i] << " ";
cout << endl;
return 0;
}
C++代码,方法4,看上去代码更简单
void poa(int a[], int n, int out[]) {
if (a==NULL || n<=1) return;
// assume out is always valid
out[n-1] = 1;
for (int i=n-2; i>=0; i--) out[i] = out[i+1] * a[i+1];
int left = 1;
for (int i=1; i<n; i++) {
left *= a[i-1]; // 这里注意顺序,容易出错,可以参考之前模拟计算时的顺序
out[i] *= left;
}
}