题目
给你一个长度为 n 的整数数组 nums,其中 n > 1,返回输出数组 output ,其中 output[i] 等于 nums 中除 nums[i] 之外其余各元素的乘积。
示例:
输入: [1,2,3,4]
输出: [24,12,8,6]
提示:题目数据保证数组之中任意元素的全部前缀元素和后缀(甚至是整个数组)的乘积都在 32 位整数范围内。
说明: 请不要使用除法,且在 O(n) 时间复杂度内完成此题。
分析:
不能使用除法,而且时间复杂度是O(n) ,那么暴力循环就不能使用了。所以就要通过发现规律进行解决了。假设一个数组的元素为m0,m2,m3,……,mn-1 ,按照题意,结果数组中:
num0 = m1 * m2 * m3 * ……mn-1
num1 = m0 * m2 * m3 * ……mn-1
num2 = m0 * m1 * m3 * ……mn-1
num3 = m0 * m1 * m2 * ……mn-1
……
numn-1 = m0 * m2 * m3 * ……mn-2
通过观察以上的式子,会发现结果数组中,它的每个结果都是由两部分乘积组成的:
比如第i个结果,它对应了原始数组中除了第i个数以外其他所有数的乘积,
这个结果的乘积因子都是原始数组中除第i个数以外的元素,那么可以分为两个部分,即一部分因子在原始数组中位于第i个数的前面,另一部分位于第i个数的后面
那么这些我们在求结果数组中的每一个数的时候,就可以考虑分成两步求:
第一步求位于第i个数左边的因子乘积,这个可以通过向左遍历原始数组,然后累乘求出第i个数的左边所有数的乘积;
第二步求位于第i个数右边的因子乘积,这个可以通过向右遍历原始数组,然后累乘求出第i个数的右边所有数的乘积
而对于第0个数和第n-1个数,它们都只有单侧的因子乘积,那么我们向左遍历完,就能求出结果数组最后一个元素的结果,向右遍历完,也可以求出结果数组中的第一个结果,但是注意,结果数组初始化时,要将第一个值初始化为1,否则会求出0这个结果;
我们定义一个结果数组,两个累乘变量即left_product和right_product,分别表示求左边因子乘积时的累乘结果,和求右边乘积时的累乘结果。因为首尾两个数都只有单侧因子,所以我们分别从第1个和第n-2个开始求单侧因子乘积
代码如下:
public int[] productExceptSelf(int[] nums) {
int n = nums.length;
int[] res = new int[n];
if (n == 2){
res[0] = nums[1];
res[1] = nums[0];
return res;
}
int left_product = 1;
res[0] = 1;
for (int i = 1; i < n; i++) {
left_product *= nums[i-1];
res[i] = left_product;
}
int right_product = 1;
for (int i = n-2; i >=0 ; i--) {
right_product *= nums[i+1];
res[i] *= right_product;
}
return res;
}