java数据结构与算法刷题-----LeetCode238. 除自身以外数组的乘积

java数据结构与算法刷题目录(剑指Offer、LeetCode、ACM)-----主目录-----持续更新(进不去说明我没写完):https://blog.csdn.net/grd_java/article/details/123063846

在这里插入图片描述

本题的难点在于,题目要求不能用除法,还不能用额外的空间(除了返回答案所必须)

1. 动态规划:左右乘积列表

解题思路:时间复杂度O( n n n),空间复杂度O( n n n).这个方法只实现了题目要求的不用除法和线性时间复杂度。空间复杂度没有考虑,会在法二中优化
  1. 题目的要求是,对于数组中nums[i],我们要求answer[i]正好是丢弃nums[i]它本身,然后求其余所有元素的乘积。

因此我们将其抽象为:[L区域]i本身[R区域]。也就是求出L和R区域的乘积后,将L和R相乘,就是answer[i] = [L区域]*[R区域]

  1. 创建两个一维dp数组L和R,分别代表下标i左边所有元素乘积,和下标i右边所有元素乘积。
  2. 这样对于nums[i],就有了两个乘积,分别代表它左边区域和右边区域的乘积,正好不带i自己玩。
  3. 最后我们将i两边乘积相乘,就正好得到了题目要求的结果。那就是整个数组除了i以外都相乘在一起。
代码

在这里插入图片描述

class Solution {
    public int[] productExceptSelf(int[] nums) {
        int length = nums.length;

        // L 和 R 分别表示左右两侧的乘积列表
        int[] L = new int[length];
        int[] R = new int[length];

        int[] answer = new int[length];

        // L[i] 为索引 i 左侧所有元素的乘积
        // 对于索引为 '0' 的元素,因为左侧没有元素,所以 L[0] = 1,因为任何数a*1都为a,不能设置为0
        L[0] = 1;
        for (int i = 1; i < length; i++) {//而其余的L[i]都是前面的结果L[i-1]的基础上 * nums[i-1]
            L[i] = nums[i - 1] * L[i - 1];
        }

        // R[i] 为索引 i 右侧所有元素的乘积
        // 对于索引为 'length-1' 的元素,因为右侧没有元素,所以 R[length-1] = 1
        R[length - 1] = 1;
        for (int i = length - 2; i >= 0; i--) {
            R[i] = nums[i + 1] * R[i + 1];
        }

        // 对于索引 i,除 nums[i] 之外其余各元素的乘积就是左侧所有元素的乘积乘以右侧所有元素的乘积
        for (int i = 0; i < length; i++) {
            answer[i] = L[i] * R[i];
        }

        return answer;
    }
}

2. 滚动数组对动态规划过程优化

解题思路:时间复杂度O( n n n),空间复杂度O( 1 1 1)
  1. 将上面动态规划的思路换为滚动数组,因为我们发现,result[1]只取决于上次的结果,所以dp数组是不必要的。
  2. 我们先将L区域直接规划到result中
  3. 然后在规划R的途中,直接将L*R规划到result中
代码

在这里插入图片描述

class Solution {
    public int[] productExceptSelf(int[] nums) {
        int size = nums.length;//长度
        int[] result = new int[size];//结果数组
        //L区域,初始k为1
        int L = 1;//代表L[0]=1;
        for (int i = 0; i <= size - 1; ++i) {//直接将L规划到result数组中
            result[i] = L;//i位置的左区域乘积为k
            L *= nums[i];//下一次的i+1位置为i位置的左区域乘积K * i位置本身nums[i]
        }
        //R区域
        int R = 1;//R[size-1] = 1;
        for (int i = size - 1; i >= 0; --i) {
            result[i] *= R;//L[i]*R[i]
            R *= nums[i];//R[i-1] = R[i] * nums[i]
        }

        return result;//返回
    }
}
  • 25
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

殷丿grd_志鹏

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值