力扣面试经典算法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;
    }
}

结果

运行代码,结果符合:

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

总结

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

加油!!!

相关推荐
AI街潜水的八角2 分钟前
基于C++的决策树C4.5机器学习算法(不调包)
c++·算法·决策树·机器学习
追风林4 分钟前
mac m1 docker本地部署canal 监听mysql的binglog日志
java·docker·mac
芒果披萨18 分钟前
El表达式和JSTL
java·el
白榆maple27 分钟前
(蓝桥杯C/C++)——基础算法(下)
算法
JSU_曾是此间年少31 分钟前
数据结构——线性表与链表
数据结构·c++·算法
sjsjs1138 分钟前
【数据结构-合法括号字符串】【hard】【拼多多面试题】力扣32. 最长有效括号
数据结构·leetcode
duration~1 小时前
Maven随笔
java·maven
zmgst1 小时前
canal1.1.7使用canal-adapter进行mysql同步数据
java·数据库·mysql
跃ZHD1 小时前
前后端分离,Jackson,Long精度丢失
java
此生只爱蛋1 小时前
【手撕排序2】快速排序
c语言·c++·算法·排序算法