Product of Array Except Self

探讨了在不使用除法的情况下计算数组中除当前元素外的所有元素乘积的有效算法。提出了四种解决方案,包括暴力计算、保留总乘积并进行除法、使用左右乘积数组以及优化的空间复杂度为O(1)的方法。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >



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;
	}
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值