【Leetcode016】除自身以外数组的乘积

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)
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值