题意描述:
给定长度为 n
的整数数组 nums
,其中 n > 1
,返回输出数组 output
,其中 output[i]
等于 nums
中除 nums[i]
之外其余各元素的乘积。
说明:
请不要使用除法,且在 O(n) 时间复杂度内完成此题。
进阶:
你可以在常数空间复杂度内完成这个题目吗?( 出于对空间复杂度分析的目的,输出数组不被视为额外空间。)
示例:
输入: [1,2,3,4]
输出: [24,12,8,6]
解题思路:
Alice: 我有点不明白,为什么不让用除法呢?
Bob: 可能是会溢出 ?
Alice: 不应该啊,返回的是一个整型数组,也就是说每 n-1 元素连乘起来是不超过整型的。就算是会溢出 ,用一个长整型应该也可以搞定了。
Bob: 哦,有一个问题,就是如果数组中有 0 的话就不好弄了。
Alice: emm, 用除法的做法是先求出整个数组的乘积,然后再除去对应的元素就是我们想要的答案了。
Bob:如果数组中有 0 的话,就会出现 0 / 0 这种非法的式子。
Alice: 把这种情况当成边界值来处理不就好了,如果有一个 0,除了这个 0 对应的乘积全是 0。如果有两个 0,那么所有元素对应的乘积就全部都是 0 了。
Bob: 哟!😎😎
-------------------------------------------------------------- Alice & Bob --------------------------------------------------------------
Alice: 哦,原来不让用除法就是为了为了避免 数组里面有 0 的问题。官方题解给的方法就是将连乘拆成 左右两个部分,用两次循环来完成,这样就避免了除法。
Bob: 那那个O(1)的内存消耗是怎么做到的呢 ?
Alice: 将连乘拆成左右两个部分,先用一个数组记录每个元素左侧所有元素的连乘积,然后用另一个变量 循环累乘 右侧的所有元素,再将两侧的积乘起来。
Bob: 原来如此,题目里面说输出数组不被视为额外空间,那么应该是吧 累乘变量之积乘到 左侧的数组上去了吧。
Alice: 是的😎😎。
代码:
Python 方法一: 连乘然后用除法。┓( ´∀` )┏
class Solution:
def productExceptSelf(self, nums: List[int]) -> List[int]:
zeroCnt = 0
zeroIndex = -1
# 统计数组里面0的个数以及最后一个0出现的下标
product = 1
# 除了 0 之外的所有 元素的乘积
for x in range(len(nums)):
if nums[x] == 0:
zeroCnt += 1
zeroIndex = x
else:
product *= nums[x]
if zeroCnt >= 2:
# 如果有两个及以上的零,那么每个元素的对应的乘积都是 0。
ans = [0 for x in range(len(nums))]
elif zeroCnt == 1:
# 如果只有一个0,只有 0 元素对应非 0 的结果,其余元素对应的都是 0。
ans = [0 for x in range(len(nums))]
ans[zeroIndex] = product
else:
# 如果数组中没有 0,将数组的连乘积 除以对应的元素即可。
ans = []
for x in nums:
ans.append(product // x)
return ans
Java 方法一: 连乘 加 除法
class Solution {
public int[] productExceptSelf(int[] nums) {
int length = nums.length;
int zeroCnt = 0;
int zeroIndex = 0;
int product = 1;
for(int i=0; i<length; ++i){
if(nums[i] == 0){
zeroCnt++;
zeroIndex = i;
}else{
product *= nums[i];
}
}
int [] answer = new int[length];
if(zeroCnt >= 2){
for(int i=0; i<length; ++i){
answer[i] = 0;
}
}else if(zeroCnt == 1){
for(int i=0; i<length; ++i){
answer[i] = 0;
}
answer[zeroIndex] = product;
}else{
for(int i=0; i<length; ++i){
answer[i] = product / nums[i];
}
}
return answer;
}
}
Python 方法二: 将连乘拆分为左右两部分,使用两遍循环完成。
class Solution:
def productExceptSelf(self, nums: List[int]) -> List[int]:
answer = [1 for x in range(len(nums))]
for x in range(1, len(nums)):
answer[x] = answer[x-1] * nums[x-1]
rightProduct = 1
for z in range(len(nums)-2, -1, -1):
rightProduct *= nums[z+1]
answer[z] *= rightProduct
return answer
Java 方法二: 将连乘拆分为左右两部分,使用两遍循环完成。
class Solution {
public int[] productExceptSelf(int[] nums) {
int[] answer = new int[nums.length];
answer[0] = 1;
// 初始化
for(int i=1; i<nums.length; ++i){
answer[i] = answer[i-1] * nums[i-1];
}
// 求出任何一个元素的左侧乘积
int rightProduct = 1;
for(int i=nums.length-2; i>=0; --i){
rightProduct *= nums[i+1];
answer[i] *= rightProduct;
}
// 再求出右侧乘积 和 最终的乘积
return answer;
}
}
易错点:
- 一些测试样例:
[1,2,3,4]
[12,2]
[1,0]
[1,0,0]
- 答案:
[24,12,8,6]
[2,12]
[0,1]
[0,0,0]
总结: