我们先来看下题目:
函数接口:
int* productExceptSelf(int* nums, int numsSize, int* returnSize)
{
}
(注:nums为数组首地址,numsSize为数组元素个数,returnSize为返回数组中元素的个数)
我们看到这个题目,相信大多数人脑海中第一个浮现的想法是:
1、遍历数组,算出数组所有元素的乘积。
2、再次遍历数组,用第一步得到的答案分别对数组元素做除,并将结果存入一个新的数组。
可是题目要求我们不能使用除法 ,这意味着我们只能使用乘法,将数组每个元素以外的所有元素的乘积都计算出来。可是如果数组包含的元素非常多,那么这样计算的时间复杂度将会极大。
我们有没有方法可以降低程序的复杂度呢?这里我们来引入一个方法:求数组的前缀积与后缀积。
前缀积(Prefix Product)方法:
- 首先创建一个与原数组相同长度的结果数组,初始化值为1。
- 从左到右遍历原数组,每次将当前元素与其前一个元素的前缀积相乘,并更新结果数组的值。
- 最终结果数组中的每个元素即为该位置之前所有元素的乘积。
后缀积(Suffix Product)方法:
- 首先创建一个与原数组相同长度的结果数组,初始化值为1。
- 从右到左遍历原数组,每次将当前元素与其后一个元素的后缀积相乘,并更新结果数组的值。
- 最终结果数组中的每个元素即为该位置之后所有元素的乘积。
我们了解思路后,下一步就是用代码实现我们的思想:
1、我们首先定义两个数组分别储存计算出的前缀积与后缀积,由于是乘法,我们先将prefix数组第一个元素和suffix数组最后一个元素都初始化为1。(也可以将遍历数组使所有元素都初始化为1)
int prefix[100000];
prefix[0]=1;
int suffix[100000];
suffix[numsSize-1]=1;
举一个例子:数组元素为 {1,2,3,4,5,6} ,当 i = 2时,nums[2] = 3。此时我们需要求除 3 以外其他所有元素的乘积。此时prefix[2]=1*2,suffix[2]=4*5*6。随着 i 的增加,前缀积逐渐增大,后缀积逐渐变小。所以我们数组设计的思路就是:随着下标逐渐增大,前缀积增大,后缀积减小。
2、前缀积(prefix)的计算 :
for(i = 0;i < numsSize; i++)
{
prefix[i+1] = prefix[i] * nums[i];
}
我们采用累乘的思路求出每个元素的前缀积,并记录下来。
3、 后缀积(suffix)的计算:
for (i = 1; i < numsSize; i++)
{
suffix[numsSize - 1 - i] = suffix[numsSize - i] * nums[numsSize - i];
}
4、将 每一个元素的前缀积与后缀积相乘 即为除自身以外数组元素的乘积。
使用malloc函数向内存申请空间,创建一个新数组 arr ,用来返回除自身以外数组元素的乘积。
int *arr = (int *)malloc(numsSize*sizeof(int));
for(i = 0;i < numsSize; i++)
{
arr[i] = prefix[i] * suffix[i];
}
return arr;
下面,我们写出完整代码:
int* productExceptSelf(int* nums, int numsSize, int* returnSize) {
int prefix[100000];
prefix[0] = 1;
int suffix[100000];
suffix[numsSize - 1] = 1;
int* arr = (int*)malloc(numsSize * sizeof(int));
int i;
for (i = 0; i < numsSize; i++)
{
prefix[i + 1] = prefix[i] * nums[i];
}
for (i = 1; i < numsSize; i++)
{
suffix[numsSize - i - 1] = suffix[numsSize - i] * nums[numsSize - i];
}
for (i = 0; i < numsSize; i++)
{
arr[i] = prefix[i] * suffix[i];
}
*returnSize = numsSize;
return arr;
}