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

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

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

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

问题描述

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

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

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

  • 示例 1:

    • 输入:

      nums = [1,2,3,4]

    • 输出:

      24,12,8,6

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

  • 示例 2:

    • 输入:

      nums = [-1,1,0,-3,3]

    • 输出:

      0,0,9,0,0

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

题目分析

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

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

  • 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;
    }
}

结果

运行代码,结果符合:

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

总结

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

加油!!!

相关推荐
Aczone2815 分钟前
嵌入式 数据结构学习 (六) 树、哈希表与内核链表
数据结构·学习·算法
定偶16 分钟前
进制转换小题
c语言·开发语言·数据结构·算法
hnlucky25 分钟前
《Nginx + 双Tomcat实战:域名解析、静态服务与反向代理、负载均衡全指南》
java·linux·服务器·前端·nginx·tomcat·web
hnlucky26 分钟前
同时部署两个不同版本的tomcat要如何配置环境变量
java·服务器·http·tomcat·web
体系结构论文研讨会1 小时前
多项式环及Rq的含义
算法
智驱力人工智能1 小时前
极端高温下的智慧出行:危险检测与救援
人工智能·算法·安全·行为识别·智能巡航·高温预警·高温监测
旷世奇才李先生1 小时前
奇哥面试记:SpringBoot整合RabbitMQ与高级特性,一不小心吊打面试官
spring boot·面试·java-rabbitmq
森焱森1 小时前
60 美元玩转 Li-Fi —— 开源 OpenVLC 平台入门(附 BeagleBone Black 驱动简单解析)
c语言·单片机·算法·架构·开源
yngsqq1 小时前
netdxf—— CAD c#二次开发之(netDxf 处理 DXF 文件)
java·前端·c#
mrsk1 小时前
🧙‍♂️ CSS中的结界术:BFC如何拯救你的布局混乱?
前端·css·面试