【LeetCode】238. 除自身以外数组的乘积

leetcode

 

解题思路

该问题要求计算数组中每个元素除自身外的乘积,且不能使用除法。核心思路是通过两次遍历(前缀积与后缀积)来避免重复计算,实现时间复杂度 O(n) 和空间复杂度 O(1)(不考虑输出数组)。

关键步骤

  1. ​​前缀积计算​​:从左到右遍历数组,计算每个元素左侧所有元素的乘积并存入结果数组 answer
  2. ​​后缀积计算​​:从右到左遍历数组,动态计算右侧元素的累积乘积,并与前缀积相乘更新 answer
  3. ​​空间优化​​:复用 answer 数组存储中间结果,仅用临时变量 right 存储右侧累积乘积。

代码实现

func productExceptSelf(nums []int) []int {
    n := len(nums)
    answer := make([]int, n)
    
    // 计算前缀积(左侧乘积)
    answer[0] = 1
    for i := 1; i < n; i++ {
        answer[i] = answer[i-1] * nums[i-1]
    }
    
    // 计算后缀积(右侧乘积)并更新答案
    right := 1
    for i := n-2; i >= 0; i-- {
        right *= nums[i+1]   // 累积右侧乘积
        answer[i] *= right   // 左乘积 * 右乘积
    }
    
    return answer
}

代码解析

  1. ​​初始化​​:创建结果数组 answer,长度为 n
  2. ​​前缀积填充​​(时间复杂度 O(n)):
    • answer[0] 初始化为 1(第一个元素左侧无元素)。
    • 遍历时,每个 answer[i] 等于前一个前缀积 answer[i-1] 与 nums[i-1] 的乘积。
  3. ​​后缀积计算​​(时间复杂度 O(n)):
    • 从右向左遍历,变量 right 累积右侧元素的乘积。
    • 每次更新 answer[i] 为前缀积与后缀积的乘积。
  4. ​​空间优化​​:仅使用 right 变量存储右侧累积乘积,无需额外数组。

示例测试

func main() {
    nums1 := []int{1, 2, 3, 4}
    fmt.Println(productExceptSelf(nums1)) // 输出: [24 12 8 6]
    
    nums2 := []int{-1, 1, 0, -3, 3}
    fmt.Println(productExceptSelf(nums2)) // 输出: [0 0 9 0 0]
}

复杂度分析

  • ​​时间复杂度​​:O(n),两次独立遍历数组。
  • ​​空间复杂度​​:O(1)(不考虑输出数组)。若包含输出数组则为 O(n),但题目明确输出数组不计入空间复杂度。

关键点

  • ​​避免除法​​:通过分解为左右乘积,规避除法带来的边界问题(如元素为 0)。
  • ​​动态更新​​:第二次遍历时直接复用 answer 数组,减少空间浪费。
  • ​​边界处理​​:正确处理数组首尾元素的左右乘积(如 i=0 时左侧无元素,i=n-1 时右侧无元素)。
posted @ 2025-04-25 10:46  云隙之间  阅读(33)  评论(0)    收藏  举报