题目描述:238. 除自身以外数组的乘积 - 力扣(LeetCode)
给你一个整数数组
nums
,返回 数组answer
,其中answer[i]
等于nums
中除nums[i]
之外其余各元素的乘积 。题目数据 保证 数组
nums
之中任意元素的全部前缀元素和后缀的乘积都在 32 位 整数范围内。请不要使用除法,且在
O(n)
时间复杂度内完成此题。
容易想到,但不正确的解法:
(1)如果你想使用暴力不考虑其他的因素的话,将所有数据乘积起来,然后遍历数组除以当前位置数据但其实是不可行的:一方面,本题要求不能使用除法;另一方面,就算可以使用除法,除法也不能解决问题,当我们遇到这种情况时: int nums[] = {0, 2, 3, 4},利用这种方法,算得的所有乘积结果是0,那么nums中第一个对应的答案是0/0,但其实nums中第一个对应的答案应该是2*3*4,并且0不能作为除数。
(2)我们可以利用双重循环,外层循环用来遍历nums中的每一个数,内层循环用来将 除外层循环对应下标的数之外的数乘积在一起(下标不相等的进行乘积)。但是这种方法的时间复杂度是O(N^2),也不符合题意。
正确的解法:
思路:
将乘积分为两次进行:
第一次先将每个位置左边的数据乘积计算出来放到返回数组的对应位置中,后边第二次循环,将对应位置右边的数据乘积计算出来与返回数组对应位置的左半边乘积相乘得到结果。
在计算左侧乘积时,如果是最左侧(第一个)的数字 ,因其左侧没有数字,该位置的左侧乘积就是1;
在计算右侧乘积时,如果是最右侧(最后一个)的数字 ,因其右侧没有数字,该位置的右侧乘积就是1;
示例: 一个数组 int nums[] = {2, 3, 4}。
int left = 1, right = 1;
计算左侧乘积:
第0个元素的左边乘积, arr[0] = left 然后计算第1位左侧乘积,left*=nums[0] -> left = 1*2;
第1个元素的左边乘积,arr[1] = left 然后计算第2位左侧乘积,left*=nums[1] -> left = 1*2*3
第2个元素的左边乘积, arr[2] = left 然后计算第3位左侧乘积,已经没必要了,因为第2元素是末尾元素了
一次循环完毕后,返回数组中每个元素存储的都是自己左侧元素的乘积。 arr[]中的值: [1, 2, 6]
计算右侧乘积:
第2个元素的右边乘积, arr[2] *= right 然后计算第1位右侧乘积,right*=nums[2] -> right =1*4;
第1个元素的右边乘积, arr[1] *= right 然后计算第0位右侧乘积,right*=nums[1] -> right =1*4*3
第0个元素的右边乘积, arr[0] *= right 然后计算第-1位右侧乘积 -1位已经不需要计算了
循环完毕后,返回数组中的每个元素都是其他元素的乘积了 arr[2]*=1; arr[1]*=4; arr[0]*=12
代码:
int* productExceptSelf(int* nums, int numsSize, int* returnSize)
{
*returnSize = numsSize;
int* answer = (int*)malloc(sizeof(int)*numsSize);
int left = 1, right = 1;
// 第一次循环用来计算左侧乘积
for(int i=0;i<numsSize;i++)
{
answer[i] = left;
left*=nums[i];
}
// 第二次循环用来计算右侧乘积得到结果
for(int i=numsSize-1;i>=0;i--)
{
answer[i]*=right;
right*=nums[i];
}
return answer;
}
本次内容到此结束了!如果你觉得这篇博客对你有帮助的话 ,希望你能够给我点个赞,鼓励一下我。感谢感谢……