238、除自身以外数组的乘积
给你一个长度为 n 的整数数组 nums,其中 n > 1,返回输出数组 output ,其中 output[i] 等于 nums 中除 nums[i] 之外其余各元素的乘积。
示例:
输入: [1,2,3,4]
输出: [24,12,8,6]
提示:题目数据保证数组之中任意元素的全部前缀元素和后缀(甚至是整个数组)的乘积都在 32 位整数范围内。
说明: 请不要使用除法,且在 O(n) 时间复杂度内完成此题。
进阶:
你可以在常数空间复杂度内完成这个题目吗?( 出于对空间复杂度分析的目的,输出数组不被视为额外空间。)
方法一:左右乘积列表
1.1 思路分析
刚开始没理解题意,看了题解才明白题没读仔细。比如[1,2,3,4],output[0]=2*3*4,除了nums[0]其他位置上的数的乘积。
最简单的是得到所有数的乘积,然后除以当前位置的数。不过遇到零就惨了,所以本题要求不可使用除法。
暴力破解又会用到双层循环,得想办法把计算的中间结果维护一下。这时候想到了动态规划和前后缀,动态规划需要动态转移方程,本来就不咋会,也没搞出动态转移方程。
题解中给出前后缀乘积列表,定义两个数组,分别记录 i 左右两边的乘积,最后构造结果时,只需将L[i]和R[i]相乘就可以得到output[i]。直接盗图了:
这里的L[0]和R[n-1]设为1,因为两边都没有数。
1.2 代码实现
func productExceptSelf(nums []int) []int {
n := len(nums)
L, R, ans := make([]int, n), make([]int, n), make([]int, n)
L[0], R[n-1] = 1, 1
for i:=1; i<n; i++{
L[i] = L[i-1] * nums[i-1]
}
for i:=n-2;i>=0;i--{
R[i] = R[i+1] * nums[i+1]
}
for i:=0; i<n; i++{
ans[i] = L[i] * R[i]
}
return ans
}
1.3 测试结果
1.4 复杂度
- 时间复杂度:O(N)。三个并列循环
- 空间复杂度:O(N)。两个额外数组 + 一个结果数组
方法二:优化空间复杂度O(1)
2.1 思路分析
其实也没啥,就是挤一挤总会有的。把结果空间临时当作左侧乘积数组,右侧乘积不维护数组,按索引顺序乘到结果空间中。
2.2 代码实现
func productExceptSelf(nums []int) []int {
n := len(nums)
ans := make([]int, n)
// 左侧数组
ans[0] = 1
for i:=1; i<n; i++{
ans[i] = ans[i-1] * nums[i-1]
}
//fmt.Println(ans)
// 右侧数组
R := 1
for j:=n-2; j>=0; j--{
//fmt.Println(R)
R = R * nums[j+1]
ans[j] = ans[j] * R
}
return ans
}
2.3 测试结果
2.4 复杂度
- 时间复杂度:O(N)
- 空间复杂度:O(1)