LeetCode题练习与总结:乘积最大子数组--152

一、题目描述

给你一个整数数组 nums ,请你找出数组中乘积最大的非空连续

子数组(该子数组中至少包含一个数字),并返回该子数组所对应的乘积。

测试用例的答案是一个 32-位 整数。

示例 1:

输入: nums = [2,3,-2,4]
输出: 6
解释: 子数组 [2,3] 有最大乘积 6。

示例 2:

复制代码
输入: nums = [-2,0,-1]
输出: 0
解释: 结果不能为 2, 因为 [-2,-1] 不是子数组。

提示:

  • 1 <= nums.length <= 2 * 10^4
  • -10 <= nums[i] <= 10
  • nums 的任何前缀或后缀的乘积都 保证 是一个 32-位 整数

二、解题思路

这个问题是求解最大乘积子数组,可以采用动态规划的方法来解决。由于数组中存在负数,而负数乘以负数会变成正数,所以最大的乘积可能来自于当前最大值的累积,也可能来自于当前最小值的累积(如果当前元素是负数的话)。因此,在遍历数组的过程中,我们需要同时记录当前的最大乘积和最小乘积。

解题思路如下:

  1. 初始化两个变量,imax和imin,分别用来存储到当前位置为止的最大乘积和最小乘积。同时,需要一个变量max用来记录全局的最大乘积。

  2. 遍历数组,对于每个元素num,更新imax和imin:

  • 如果num大于0,那么imax和imin分别乘以num,更新它们的值。
  • 如果num小于0,那么imax和imin交换,因为负数乘以较小的数会得到更大的数。
  • 更新全局最大乘积max。
  1. 遍历完成后,max就是我们要找的最大乘积。

三、具体代码

java 复制代码
public class Solution {
    public int maxProduct(int[] nums) {
        if (nums == null || nums.length == 0) {
            return 0;
        }
        
        int max = nums[0]; // 全局最大乘积
        int imax = nums[0]; // 当前最大乘积
        int imin = nums[0]; // 当前最小乘积
        
        for (int i = 1; i < nums.length; i++) {
            if (nums[i] < 0) {
                // 如果当前元素是负数,交换imax和imin
                int temp = imax;
                imax = imin;
                imin = temp;
            }
            
            // 更新最大乘积和最小乘积
            imax = Math.max(nums[i], imax * nums[i]);
            imin = Math.min(nums[i], imin * nums[i]);
            
            // 更新全局最大乘积
            max = Math.max(max, imax);
        }
        
        return max;
    }
}

四、时间复杂度和空间复杂度

1. 时间复杂度
  • 该算法包含一个循环,循环次数与输入数组nums的长度成正比,记为n
  • 在循环内部,每次迭代都执行了常数时间的操作,包括比较、乘法、赋值和更新最大值。
  • 因此,整个算法的时间复杂度是O(n),其中n是数组nums的长度。
2. 空间复杂度
  • 该算法只使用了固定数量的额外空间,即imaximinmax这三个整数变量,不管输入数组nums的大小如何,所使用的额外空间都保持不变。
  • 因此,空间复杂度是O(1),即常数空间复杂度。

综上所述,该算法的时间复杂度是O(n),空间复杂度是O(1)。这意味着算法的运行时间随着输入数组大小的增加而线性增加,而所需的额外空间不会随着输入数组大小的增加而增加。

五、总结知识点

  1. 动态规划:这是一种在数学、管理科学、计算机科学、经济学和生物信息学等领域中使用的,通过把原问题分解为相对简单的子问题的方式来求解复杂问题的方法。在这个问题中,我们通过维护当前的最大乘积和最小乘积来找到全局最大乘积。

  2. 分治思想:虽然代码中没有直接使用分治算法,但是动态规划可以看作是分治思想的一个特例。分治思想是将一个问题分解成若干个规模较小的相同问题,然后将这些小问题的解决方案合并起来解决原来的问题。

  3. 贪心算法:在每一步选择中都采取在当前状态下最好或最优的选择,希望通过局部最优的选择达到全局最优的结果。在这个问题中,我们每次都选择是当前最大乘积或最小乘积的累积,这是基于当前状态的局部最优选择。

  4. 边界条件处理 :在代码的开始部分,对输入数组nums进行了空值和长度的检查,这是一种常见的编程实践,用于处理边界情况,避免空指针异常或逻辑错误。

  5. 数学运算:代码中使用了乘法和比较运算符来计算乘积和比较大小,这是编程中基本的数学操作。

  6. 循环结构 :使用for循环来遍历数组,这是编程中常用的控制结构,用于重复执行一系列操作。

  7. 条件语句 :使用if语句来检查当前元素是否为负数,并根据条件执行不同的代码块,这是编程中用于分支选择的基本结构。

  8. 变量交换 :在遇到负数时,通过引入临时变量temp来交换imaximin的值,这是一种常见的编程技巧。

  9. 数学函数的使用 :使用Math.maxMath.min函数来获取两个数中的最大值和最小值,这是Java标准库中提供的实用函数。

以上就是解决这个问题的详细步骤,希望能够为各位提供启发和帮助。

相关推荐
晨曦_子画4 分钟前
编程语言之战:AI 之后的 Kotlin 与 Java
android·java·开发语言·人工智能·kotlin
软工菜鸡24 分钟前
预训练语言模型BERT——PaddleNLP中的预训练模型
大数据·人工智能·深度学习·算法·语言模型·自然语言处理·bert
南宫生27 分钟前
贪心算法习题其三【力扣】【算法学习day.20】
java·数据结构·学习·算法·leetcode·贪心算法
Heavydrink40 分钟前
HTTP动词与状态码
java
ktkiko1143 分钟前
Java中的远程方法调用——RPC详解
java·开发语言·rpc
AI视觉网奇1 小时前
sklearn 安装使用笔记
人工智能·算法·sklearn
计算机-秋大田1 小时前
基于Spring Boot的船舶监造系统的设计与实现,LW+源码+讲解
java·论文阅读·spring boot·后端·vue
神里大人1 小时前
idea、pycharm等软件的文件名红色怎么变绿色
java·pycharm·intellij-idea
JingHongB1 小时前
代码随想录算法训练营Day55 | 图论理论基础、深度优先搜索理论基础、卡玛网 98.所有可达路径、797. 所有可能的路径、广度优先搜索理论基础
算法·深度优先·图论
weixin_432702261 小时前
代码随想录算法训练营第五十五天|图论理论基础
数据结构·python·算法·深度优先·图论