
| 🚀 算法题 🚀 | 
🌲 算法刷题专栏 | 面试必备算法 | 面试高频算法 🍀
🌲 越难的东西,越要努力坚持,因为它具有很高的价值,算法就是这样✨
🌲 作者简介:硕风和炜,CSDN-Java领域新星创作者🏆,保研|国家奖学金|高中学习JAVA|大学完善JAVA开发技术栈|面试刷题|面经八股文|经验分享|好用的网站工具分享💎💎💎
🌲 恭喜你发现一枚宝藏博主,赶快收入囊中吧🌻
🌲 人生如棋,我愿为卒,行动虽慢,可谁曾见我后退一步?🎯🎯
| 🚀 算法题 🚀 | 

🍔 目录
- 🚗 知识回顾
- 🚩 题目链接
- ⛲ 题目描述
- 🌟 求解思路&实现代码&运行结果
- ⚡ 暴力递归
- 🥦 求解思路
- 🥦 实现代码
- 🥦 运行结果
 
- ⚡ 记忆化搜索
- 🥦 求解思路
- 🥦 实现代码
- 🥦 运行结果
 
- ⚡ 动态规划
- 🥦 求解思路
- 🥦 实现代码
- 实现方式1
- 实现方式2
 
- 🥦 运行结果
 
 
- 💬 共勉
 
🚗 知识回顾
大家再看这道题目之前,可以先去看一下我之前写过的一篇关于连续子数组算法题的博客,再看这个题目就更容易理解了。
 博客的地址放到这里了,可以先去学习一下这到题目。
- 【LeetCode: 53. 最大子数组和 | 暴力递归=>记忆化搜索=>动态规划 | 分治法 】
- 【LeetCode: 718. 最长重复子数组 | 暴力递归=>记忆化搜索=>动态规划】
🚩 题目链接
- 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 * 104
 -10 <= nums[i] <= 10
 nums 的任何前缀或后缀的乘积都 保证 是一个 32-位 整数
🌟 求解思路&实现代码&运行结果
⚡ 暴力递归
🥦 求解思路
- 子数组类型的题目我们同样可以从以某一位个位置结尾的情况是什么样的角度来进行一个思考。
- 这个题目区别于最大子数组和不同的是乘积最大,为什么说这个不同呢?因为当前位置的最大值可以是正数*正数,也可以是负数*负数得来的,那么某一个位置结束的最大值的情况就来源于以下三种情况:1. 前一个位置最大的值*当前位置 2.就是当前位置的值 3. 前一个位置最小的值*当前位置的数。
- 上述描述的只是一个过程,接下来我们还需要通过不断的迭代所有位置结尾的位置,得到最大的值。
- 下面就是代码的具体实现过程。
🥦 实现代码
class Solution {
    
    public int maxProduct(int[] nums) {
        int n=nums.length;
        int max=Integer.MIN_VALUE;
        for(int i=0;i<n;i++){
            max=Math.max(max,process(i,nums));
        }
        return max;
    }
    public int process(int i,int[] nums){
        if(i<0) return 1;
        return Math.max(process(i-1,nums)*nums[i],Math.max(process1(i-1,nums)*nums[i],nums[i]));
    }
    public int process1(int i,int[] nums){
        if(i<0) return 1;
        return Math.min(process1(i-1,nums)*nums[i],Math.min(process(i-1,nums)*nums[i],nums[i]));
    }
}
🥦 运行结果
时间超限了,不要紧哦,我还有锦囊妙计!

⚡ 记忆化搜索
🥦 求解思路
- 根据我们递归的分析,在递归的过程中会产生重复的子过程,所以我们想到了加一个缓存表,也就是我们的记忆化搜索。
🥦 实现代码
class Solution {
    
    int[] dp1;
    int[] dp2;
    public int maxProduct(int[] nums) {
        int n=nums.length;
        dp1=new int[n];
        dp2=new int[n];
        Arrays.fill(dp1,-1);
        Arrays.fill(dp2,-1);
        int max=Integer.MIN_VALUE;
        for(int i=0;i<n;i++){
            max=Math.max(max,process(i,nums));
        }
        return max;
    }
    public int process(int i,int[] nums){
        if(i<0) return 1;
        if(dp1[i]!=-1) return dp1[i];
        return dp1[i]=Math.max(process(i-1,nums)*nums[i],Math.max(process1(i-1,nums)*nums[i],nums[i]));
    }
    public int process1(int i,int[] nums){
        if(i<0) return 1;
        if(dp2[i]!=-1) return dp2[i];
        return dp2[i]=Math.min(process1(i-1,nums)*nums[i],Math.min(process(i-1,nums)*nums[i],nums[i]));
    }
}
🥦 运行结果

⚡ 动态规划
🥦 求解思路
- 按照我们之前递归和记忆化搜索的思路,通过动态规划实现出来。
🥦 实现代码
注意:只是代码的实现方式不同,核心的原理是一致的。
实现方式1
class Solution {
    
    int[] dp1;
    int[] dp2;
    public int maxProduct(int[] nums) {
        int n=nums.length;
        dp1=new int[n];
        dp2=new int[n];
        dp1[0]=dp2[0]=nums[0];
        int max=nums[0];
        for(int i=1;i<n;i++){
            dp1[i]=Math.max(dp1[i-1]*nums[i],Math.max(dp2[i-1]*nums[i],nums[i]));
            dp2[i]=Math.min(dp2[i-1]*nums[i],Math.min(dp1[i-1]*nums[i],nums[i]));
            max=Math.max(max,dp1[i]);
        }
        return max;
    }
}
实现方式2
class Solution {
    
    int[] dp1;
    int[] dp2;
    public int maxProduct(int[] nums) {
        int n=nums.length;
        dp1=new int[n+1];
        dp2=new int[n+1];
        dp1[n]=dp2[n]=1;
        int max=Integer.MIN_VALUE;
        for(int i=n-1;i>=0;i--){
            dp1[i]=Math.max(dp1[i+1]*nums[i],Math.max(dp2[i+1]*nums[i],nums[i]));
            dp2[i]=Math.min(dp2[i+1]*nums[i],Math.min(dp1[i+1]*nums[i],nums[i]));
            max=Math.max(max,dp1[i]);
        }
        return max;
    }
}
🥦 运行结果

💬 共勉
| 最后,我想和大家分享一句一直激励我的座右铭,希望可以与大家共勉! | 




















