力扣面试经典算法150题:除自身以外数组的乘积

除自身以外数组的乘积算法详解

今天的题目是力扣面试经典150题中的数组的中等难度题:除自身以外数组的乘积。

题目链接:https://leetcode.cn/problems/product-of-array-except-self/description/?envType=study-plan-v2&envId=top-interview-150

问题描述

给你一个整数数组 nums,返回 数组 answer ,其中 answeri 等于 nums 中除 numsi 之外其余各元素的乘积 。

题目数据 保证 数组 nums之中任意元素的全部前缀元素和后缀的乘积都在 32 位 整数范围内。

请不要使用除法,且在 O(n) 时间复杂度内完成此题。

  • 示例 1:

    • 输入:

      nums = 1,2,3,4

    • 输出:

      24,12,8,6

    • 解释: 对于每个位置 i,outputi 是 nums 中除 numsi 以外所有元素的乘积。

  • 示例 2:

    • 输入:

      nums = -1,1,0,-3,3

    • 输出:

      0,0,9,0,0

    • 解释: 对于每个位置 i,outputi 是 nums 中除 numsi 以外所有元素的乘积。

题目分析

先看题目要求,给定数组,输出一个数组,并且这个数组的每个元素的值,是给定数组除当前位置外所有元素的乘积。

我们再看示例,也很明显:

  • 24 = 2x3x4
  • 12 = 1x3x4
  • 8 = 1x2x4
  • 6 = 1x2x3
  • 0 = 1x0x-3x3
  • 0 = -1x0x-1x3
  • 9 = -1x1x-3x3
  • 0 = -1x1x0x3
  • 0 = -1x1x0x-3

那么,对题目要求我们已经明确了,再看题目其他信息:请不要使用除法,且在 O(n) 时间复杂度内完成此题。

正常情况下,这种求除自身元素外乘积的题目,直接所有元素相乘再除自身就能得到答案(求和,差,商类似),但是题目要求我们不能用除法,所以这个解法直接排除。

在 O(n) 时间复杂度内完成此题,这句话就明确了,我们解答题目,最多只能一层for循环,这样才能保证时间复杂度在O(n),但是题目没有要求空间复杂度,所以我们考虑用多个数组来实现解题。

解题思路

题目要求新数组元素的值是除自身外的所有元素的乘积,是不是可以理解为 元素左边的所有元素的乘积与元素右边所有元素的乘积再相乘呢?另外,由于首个位置的元素和最后位置的元素缺失一边的元素乘积,为了不影响结果,我们可以设定缺失的那边值为1。

由此,我们针对示例的分析可以修改如下:

  • 24 = 1(假定的左边乘积) x (2x3x4)(右边的乘积)
  • 12 = 1(左边的乘积)x(3x4)(右边的乘积)
  • 8 = (1x2)(左边的乘积)x4(右边的乘积)
  • 6 = (1x2x3)(左边的乘积)x1(假定的右边乘积)

另外在分析的时候,我们已经考虑了用多个数组实现解题,因为多个数组分多次循环,不改变时间复杂度为O(n),只是影响空间复杂度。

所以我们可以直接设定两个数组,一个数组计算元素左边的乘积,一个元素计算右边的乘积,最后相乘,即可得到答案。

当然,实际计算的时候,我们在计算第二个数组的乘积的时候,将第一个数组的乘积相乘即可。

实际算法代码

以下是使用上述思路的 Java 实现:

java 复制代码
public class ProductExceptSelf {
   public static void main(String[] args) {
        ProductExceptSelf solution = new ProductExceptSelf();
        int[] nums1 = {1, 2, 3, 4};
        int[] result1 = solution.productExceptSelf(nums1);
        System.out.println(Arrays.toString(result1)); // 输出: [24, 12, 8, 6]

        int[] nums2 = {-1, 1, 0, -3, 3};
        int[] result2 = solution.productExceptSelf(nums2);
        System.out.println(Arrays.toString(result2)); // 输出: [0, 0, 9, 0, 0]
    }

    public int[] productExceptSelf(int[] nums) {
        int length = nums.length;
        int[] answer = new int[length];

        // 从左向右计算左侧所有元素的乘积
        answer[0] = 1;
        for (int i = 1; i < length; i++) {
            answer[i] = nums[i - 1] * answer[i - 1];
        }

        // 从右向左计算右侧所有元素的乘积
        int R = 1;
        for (int i = length - 1; i >= 0; i--) {
            answer[i] = answer[i] * R;
            R *= nums[i];
        }

        return answer;
    }
}

结果

运行代码,结果符合:

提交到力扣,也通过测试:

总结

通过两个数组的方式,我们分别对左右相乘,再将最终结果相乘,成功得到答案,类似的和,差,商的题目一样的解法。做这些题目,一定要归纳总结出一些自己的东西,而不是盲目的解题,看解析。

加油!!!

相关推荐
wuqingshun3141597 分钟前
什么是责任链模式,一般用在什么场景?
java·责任链模式
:-)1 小时前
算法-归并排序
java·开发语言·数据结构·算法·排序算法
wuqingshun3141591 小时前
说一下消息队列的模型有哪些?
java
fīɡЙtīиɡ ℡2 小时前
布隆过滤器
java
yaoxin5211232 小时前
462. Java 反射 - 获取声明类与封闭类
java·开发语言·python
kyriewen3 小时前
面试官让我优化一个卡死的表格,我打开 Claude 五秒重写,他放下咖啡问我要不要来当组长
前端·javascript·面试
wuqingshun3141595 小时前
MYSQL的乐观锁和悲观锁是什么?
java
Jerry5 小时前
LeetCode 101. 对称二叉树
算法
黄敬峰5 小时前
从零搭建 RAG 应用 —— 一个故事带你彻底搞懂检索增强生成
面试
唐青枫5 小时前
Java SLF4J 实战指南:从日志门面到 Logback、MDC 和链路追踪
java