问题描述
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].
Follow up:
Could you solve it with constant space complexity? (Note: The output array does not count as extra space for the purpose of space complexity analysis.)
问题分析
给定一个数组,求出当前数组中除了自身以外的所有数的和。同时要求不能使用除法,时间复杂度为O(n)。同时空间复杂度是固定的。
常规的解法是:先把所有的数乘起来,然后除以每一个数。这当中需要单独的处理0的问题,一个0,只要计算0的哪个值,两个0则全部为0.但是不能用除法。那么用乘法,正常的想法是使用一个二次循环,系统中堵住了这条路。仔细的看一下,求得的每一个的结果是左边所有乘积的乘以右边所有数的乘积。
所以可以将所有的数的从左到右的乘积和从右到左的乘积计算出来写到一个数组中。
代码如下
public int[] productExceptSelf(int[] nums) {
int[] leftResult = new int[nums.length];
leftResult[0] = nums[0];
for (int i = 1; i < leftResult.length; i++) {
leftResult[i] = leftResult[i - 1] * nums[i];
}
int[] rightResult = new int[nums.length];
rightResult[nums.length - 1] = nums[nums.length - 1];
for (int i = nums.length - 2; i >= 0; i--) {
rightResult[i] = rightResult[i + 1] * nums[i];
}
int[] result = new int[nums.length];
result[0] = rightResult[1];
result[nums.length - 1] = leftResult[nums.length - 2];
for (int i = 1; i < nums.length - 1; i++) {
result[i] = leftResult[i - 1] * rightResult[i + 1];
}
return result;
}
算法改进
上面的算法中,使用了两个数组来存放从左到右和从右到左的中间结果。优化的过程中,可以先记录从左到右的结果,然后从右开始向左计算,不断的计算出从右向左的中间结果,然后将最终结果记录到结果数组中,返回。
代码实现
public int[] productExceptSelf(int[] nums) {
int[] result = new int[nums.length];//先乘了左边
int temp = 1;
for (int i = 0; i < nums.length; i++) {
result[i] = temp;//最低位 = 1
temp = temp * nums[i];
}
temp = 1;
for (int i = nums.length - 1; i >= 0; i--) {
result[i] = temp * result[i];
temp = temp * nums[i];
}
return result;
}
第一个循环,先把所有的左边的除了自身以外的所有的乘积记录下来。使用一个temp,先将结果赋给结果中的数组,然后在计算值,这样每次记录的结果就是上一次的值了。
第二个循环使用了类似的手法,使用一个temp记录上一次的值赋给最终结果,然后计算下一次的结果。
通过一个temp来错开多次执行的结果。