【问题描述】[中等]

给你一个整数数组 nums ,请你找出数组中乘积最大的连续子数组(该子数组中至少包含一个数字),并返回该子数组所对应的乘积。示例 1:输入: [2,3,-2,4]
输出: 6
解释: 子数组 [2,3] 有最大乘积 6。
示例 2:输入: [-2,0,-1]
输出: 0
解释: 结果不能为 2, 因为 [-2,-1] 不是子数组。

【解答思路】

1. 动态规划


时间复杂度:O(N) 空间复杂度:O(N)

public class Solution {public int maxProduct(int[] nums) {int len = nums.length;if (len == 0) {return 0;}// dp[i][0]:以 nums[i] 结尾的连续子数组的最小值// dp[i][1]:以 nums[i] 结尾的连续子数组的最大值int[][] dp = new int[len][2];dp[0][0] = nums[0];dp[0][1] = nums[0];for (int i = 1; i < len; i++) {if (nums[i] >= 0) {dp[i][0] = Math.min(nums[i], nums[i] * dp[i - 1][0]);dp[i][1] = Math.max(nums[i], nums[i] * dp[i - 1][1]);} else {dp[i][0] = Math.min(nums[i], nums[i] * dp[i - 1][1]);dp[i][1] = Math.max(nums[i], nums[i] * dp[i - 1][0]);}}// 只关心最大值,需要遍历int res = dp[0][1];for (int i = 1; i < len; i++) {res = Math.max(res, dp[i][1]);}return res;}
}
2. 动态规划优化 表格复用


时间复杂度:O(N) 空间复杂度:O(1)

public class Solution {public int maxProduct(int[] nums) {int len = nums.length;if (len == 0) {return 0;}int preMax = nums[0];int preMin = nums[0];// 滚动变量int curMax;int curMin;int res = nums[0];for (int i = 1; i < len; i++) {if (nums[i] >= 0) {curMax = Math.max(preMax * nums[i], nums[i]);curMin = Math.min(preMin * nums[i], nums[i]);} else {curMax = Math.max(preMin * nums[i], nums[i]);curMin = Math.min(preMax * nums[i], nums[i]);}res = Math.max(res, curMax);// 赋值滚动变量preMax = curMax;preMin = curMin;}return res;}
}
class Solution {public int maxProduct(int[] nums) {int max = Integer.MIN_VALUE, imax = 1, imin = 1; //一个保存最大的,一个保存最小的。for(int i=0; i<nums.length; i++){if(nums[i] < 0){ int tmp = imax; imax = imin; imin = tmp;} //如果数组的数是负数,那么会导致最大的变最小的,最小的变最大的。因此交换两个的值。imax = Math.max(imax*nums[i], nums[i]);imin = Math.min(imin*nums[i], nums[i]);max = Math.max(max, imax);}return max;}
}

【总结】

1.无后效性

无后效性是指如果在某个阶段上过程的状态已知,则从此阶段以后过程的发展变化仅与此阶段的状态有关,而与过程在此阶段以前的阶段所经历过的状态无关。利用动态规划方法求解多阶段决策过程问题,过程的状态必须具备无后效性

「动态规划」通常不关心过程,只关心「阶段结果」,这个「阶段结果」就是我们设计的「状态」。什么算法关心过程呢?「回溯算法」,「回溯算法」需要记录过程,复杂度通常较高。

而将状态定义得更具体,通常来说对于一个问题的解决是满足「无后效性」的。这一点的叙述很理论化,不熟悉朋友可以通过多做相关的问题来理解「无后效性」这个概念。

2.做题通常可以不先考虑优化空间
  • 空间通常来说是用户不敏感的,并且在绝大多数情况下,空间成本低,我们写程序通常需要优先考虑时间复杂度最优;
  • 时间复杂度和空间复杂度通常来说不可能同时最优,所以我们经常看到的是优化解法思路都是「空间换时间」,这一点几乎贯穿了基础算法领域的绝大多数的算法设计思想;
  • 限制空间的思路,通常来说比较难,一般是在优化的过程中才考虑优化空间,在一些限制答题时间的场景下(例如面试),先写出一版正确的代码是更重要的,并且不优化空间的代码一般来说,可读性和可解释性更强。
3.动态规划总结

动态规划问题通常用于计算多阶段决策问题的最优解
多阶段,是指解决一个问题有多个步骤;
最优解,是指「最优子结构」。

动态规划有三个概念很重要:
重复子问题:因为重复计算,所以需要「空间换时间」,记录子问题的最优解;
最优子结构:规模较大的问题的最优解,由各个子问题的最优解得到;
无后效性(上面已经解释)。

动态规划有两个特别关键的步骤:
设计状态:

  • 有些题目问啥,就设计成什么;
  • 如果不行,只要有利于状态转移,很多时候,就可以设计成状态;
  • 根据过往经验;
  • 还有一部分问题是需要在思考的过程中调整的,例如本题。

**推导状态转移方程:**通常是由问题本身决定的。

动态规划问题思考的两个方向:

  • 自顶向下:即「递归 + 记忆化」,入门的时候优先考虑这样做;
  • 自底向上:即「递归」,从一个最小的问题开始,逐步得到最终规模问题的解。后面问题见得多了,优先考虑这样做,绝大部分动态规划问题可以「自底向上」通过递推得到。

转载链接:https://leetcode-cn.com/problems/maximum-product-subarray/solution/dong-tai-gui-hua-li-jie-wu-hou-xiao-xing-by-liweiw/

[Leedcode][JAVA][第152题][乘积最大子数组][动态规划]相关推荐

  1. [Leedcode][JAVA][第300题][最长上上子序列][动态规划][压缩空间]

    [问题描述][中等] 给定一个无序的整数数组,找到其中最长上升子序列的长度.示例:输入: [10,9,2,5,3,7,101,18] 输出: 4 解释: 最长的上升子序列是 [2,3,7,101],它 ...

  2. [Leedcode][JAVA][第887题][鸡蛋掉落][谷歌面试][动态规划]

    [问题描述] [887. 鸡蛋掉落] 你将获得 K 个鸡蛋,并可以使用一栋从 1 到 N 共有 N 层楼的建筑.每个蛋的功能都是一样的,如果一个蛋碎了,你就不能再把它掉下去.你知道存在楼层 F ,满足 ...

  3. [Leedcode][JAVA][第22题括号生成][DFS][BFS][动态规划]

    [问题描述]22. 括号生成 数字 n 代表生成括号的对数,请你设计一个函数,用于能够生成所有可能的并且 有效的 括号组合. 示例:输入:n = 3 输出:["((()))",&q ...

  4. leetcode算法题--乘积最大子数组

    原题链接:https://leetcode-cn.com/problems/maximum-product-subarray/ 思路是用两个数组,一个最大max[],一个最小min[].然后用动态规划 ...

  5. [Leedcode][JAVA][第15题][三数之和][数组][双指针]

    [问题描述][中等] 给你一个包含 n 个整数的数组 nums,判断 nums 中是否存在三个元素 a,b,c ,使得 a + b + c = 0 ?请你找出所有满足条件且不重复的三元组.注意:答案中 ...

  6. [Leedcode][JAVA][第1014题][最佳观光组合][数组][暴力优化]

    [问题描述][中等] 给定正整数数组 A,A[i] 表示第 i 个观光景点的评分,并且两个景点 i 和 j 之间的距离为 j - i.一对景点(i < j)组成的观光组合的得分为(A[i] + ...

  7. [Leedcode][JAVA][第33题][搜索旋转排序数组]

    [问题描述][33. 搜索旋转排序数组] [中等] 假设按照升序排序的数组在预先未知的某个点上进行了旋转.( 例如,数组 [0,1,2,4,5,6,7] 可能变为 [4,5,6,7,0,1,2] ). ...

  8. [Leedcode][JAVA][第466题][统计重复个数][数组]

    [问题描述]466. 统计重复个数 由 n 个连接的字符串 s 组成字符串 S,记作 S = [s,n].例如,["abc",3]="abcabcabc".如果 ...

  9. [Leedcode][JAVA][第105题][从前序与中序遍历序列构造二叉树][栈][递归][二叉树]

    [问题描述][中等] 根据一棵树的前序遍历与中序遍历构造二叉树.注意: 你可以假设树中没有重复的元素.例如,给出前序遍历 preorder = [3,9,20,15,7] 中序遍历 inorder = ...

最新文章

  1. 2018年薪资最高的15个技术岗
  2. vs2005打开vs2008
  3. Web Service 学习笔记(2)
  4. android根据mac地址连接耳机,Android获取设备IMEI和Mac地址
  5. VS2019调试查看变量_你很可能需要知道这个调试小技巧
  6. python读取csv文件坐标地图描点_python3 通过百度地图API获取城市POI点并存于CSV格式...
  7. grid.getSelectionModel的所有操作
  8. 设备的开发【WP7学习札记之五】
  9. 深入理解 flex 布局以及计算_Flexbox, Layout
  10. jQuery实现点击显示和隐藏内容
  11. PDF文件密码破解方法有几种,快来看!
  12. 基于html的明星网站
  13. 查找算法——adjacent_find
  14. 多线程应用_左圆右方
  15. K空间的理解 倒空间
  16. 第39级台阶回溯算法c语言,五大经典算法之回溯法 - osc_9ipdey7e的个人空间 - OSCHINA - 中文开源技术交流社区...
  17. ObjectUtils.isEmpty() 和 null 区别
  18. 离线数据系统之MapReduce加强
  19. chevkv基于成对ANI的快速基因组聚类
  20. SciTe 中文设置(解决乱码,中文界面)

热门文章

  1. CodeForces 139C Literature Lesson(模拟)
  2. 《linux内核设计与实现》读书笔记第一、二章
  3. 从网络字节流中提出整数
  4. 谈自动化测试与CI中一些常见的谬见
  5. 常用的服务器系统,常用的服务器操作系统
  6. linux组类型,LINUX用户以及用户组
  7. PHP API接口GETPOST请求封装(通用)
  8. Android 图片识别、图像识别
  9. Oracle DMP 导入导出
  10. 计算机科学与技术班级口号八字,班级的八字口号