问题

//给一个整数数组 nums , // 请找出一个具有"最大和"的连续子数组(子数组最少包含一个元素), // 返回其最大和。

//子数组 是数组中的一个"连续部分"

分析

// 这是一道典型的使用「动态规划」

(连续、只要结果)解决的问题,

// 需要我们掌握动态规划问题设计状态的技巧(无后效性),

// 并且需要知道如何推导状态转移方程,

// 最后再去优化空间。

转换为若干个 子问题

连续:可以求出 ”所有“ 经过(以**结尾的)输入数组的 某一个数 的连续子数组的最大和(只要这个结果)。

如果编号为 i 的子问题的结果是负数或者 0 ,

那么编号为 i + 1 的子问题就可以把编号为 i 的子问题的结果”舍弃掉“(因为要求是最大和)

代码

main函数

package DataStructure_start;public class DS20230109 {public static void main(String[] args) {int[] nums = {-1,9,-2,3,5,6};System.out.println(maxSubArray(nums));System.out.println(maxSubArray1(nums));System.out.println(maxSubArray2(nums));System.out.println(maxSubArray3(nums));}
}

方法一:动态规划

参考1:(子数组)

时间复杂度:O(n),N是输入数组的长度

public static int maxSubArray(int[] nums) {int len = nums.length;// dp[i] 表示:以 nums[i] 结尾的连续子数组的最大和int[] dp = new int[len];dp[0] = nums[0];//        如果编号为 i 的子问题的结果是负数或者 0 ,
//        那么编号为 i + 1 的子问题就可以把编号为 i 的子问题的结果”舍弃掉“(因为要求是最大和)
//        即:如果i的子问题的结果是正数,则保留for (int i = 1; i < len; i++) {
//            如果前一个数为正数if (dp[i - 1] > 0) {
//                则再加下一个数
//                ?但只是相邻的两个数 ×
//                  dp[i] 表示:以 nums[i] 结尾的连续子数组的最大和
//                  注意区别dp[](一个连续的数组)与num[](一个数)的区别dp[i] = dp[i - 1] + nums[i];} else {dp[i] = nums[i];}}// 也可以在上面遍历的同时求出 res 的最大值,这里我们为了语义清晰分开写,大家可以自行选择int res = dp[0];for (int i = 1; i < len; i++) {res = Math.max(res, dp[i]);//调用函数Math:max函数:判断谁是最大值(三元表达式)}return res;//返回最大和}

补充:

三元表达式

public static int max(int a, int b) {

return (a >= b) ? a : b;

}

时间复杂度从小到大排序:

(由里向外分析时间复杂度;取最大的时间复杂度)

O(1) < O(logn) < O(n) < O(nlogn) < O(n^2) < O(n^3) < O(2^n) < O(n!) < O(n^n)

参考2:优化后

时间复杂度:O(n),N是输入数组的长度

public static int maxSubArray1(int[] nums) {int pre = 0;//前一个数int res = nums[0];//最大和//            只适用于数组,循环累加(优化点★)for (int num : nums) {pre = Math.max(pre + num, num);res = Math.max(res, pre);}return res;}

有后效性:

如果之前的阶段求解的子问题的结果包含了一些不确定的信息,导致了后面的阶段求解的子问题无法得到,或者很难得到,这叫「有后效性」

解决「有后效性」的办法是固定住需要分类讨论的地方,记录下更多的结果。在代码层面上表现为:

状态数组增加维度;

把状态定义得更细致、准确:状态定义只解决路径来自左右子树的其中一个子树。

需要经常思考 为什么想到需要这样定义状态。

动态规划的是首先对数组进行遍历,当前最大连续子序列和为 sum,结果为 ans

如果 sum > 0,则说明 sum 对结果有增益效果,则 sum 保留并加上当前遍历数字

如果 sum <= 0,则说明 sum 对结果无增益效果,需要舍弃,则 sum 直接更新为当前遍历数字

每次比较 sum 和 ans的大小,将最大值置为ans,遍历结束返回结果

时间复杂度:O(n)

public static int maxSubArray3(int[] nums) {int ans = nums[0];int sum = 0;//        此处类似方法一参考1中的优化部分,即for循环数组for(int num: nums) {//          正数if(sum > 0) {
//              累加sumsum += num;
//              负数,保持不变} else {sum = num;}//          三元表达式:比较取最大值ans = Math.max(ans, sum);}return ans;}

方法二:分治法(分类讨论,分成三部分)

复杂度分析:

时间复杂度:O(NlogN),这里递归的深度是对数级别的,每一层需要遍历一遍数组(或者数组的一半、四分之一);

空间复杂度:O(logN),需要常数个变量用于选取最大值,需要使用的空间取决于递归栈的深度。

连续子序列的最大和主要由这三部分子区间里元素的最大和得到:

第 1 部分:子区间 [left, mid];

第 2 部分:子区间 [mid + 1, right];

第 3 部分:包含子区间 [mid , mid + 1] 的子区间,

即 nums[mid] 与 nums[mid + 1] 一定会被选取(因为跨区。从中间向两边扩散,扩散到底 选出最大值)。

对这三个部分求最大值即可。

public static int maxSubArray2(int[] nums) {int len = nums.length;if (len == 0) {return 0;}return maxSubArraySum(nums, 0, len - 1);}private static int maxCrossingSum(int[] nums, int left, int mid, int right) {// 一定会包含 nums[mid] 这个元素int sum = 0;int leftSum = Integer.MIN_VALUE;// 左半边包含 nums[mid] 元素,最多可以到什么地方// 走到最边界,看看最值是什么// 计算以 mid 结尾的最大的子数组的和for (int i = mid; i >= left; i--) {sum += nums[i];if (sum > leftSum) {leftSum = sum;}}sum = 0;int rightSum = Integer.MIN_VALUE;// 右半边不包含 nums[mid] 元素,最多可以到什么地方// 计算以 mid+1 开始的最大的子数组的和for (int i = mid + 1; i <= right; i++) {sum += nums[i];if (sum > rightSum) {rightSum = sum;}}return leftSum + rightSum;}private static int maxSubArraySum(int[] nums, int left, int right) {if (left == right) {return nums[left];}int mid = left + (right - left) / 2;return max3(maxSubArraySum(nums, left, mid),maxSubArraySum(nums, mid + 1, right),maxCrossingSum(nums, left, mid, right));}private static int max3(int num1, int num2, int num3) {return Math.max(num1, Math.max(num2, num3));}

参考

作者:liweiwei1419

链接:https://leetcode.cn/problems/maximum-subarray/solution/dong-tai-gui-hua-fen-zhi-fa-python-dai-ma-java-dai/

来源:力扣(LeetCode)

作者:guanpengchn

链接:https://leetcode.cn/problems/maximum-subarray/solution/hua-jie-suan-fa-53-zui-da-zi-xu-he-by-guanpengchn/

来源:力扣(LeetCode)

Leetcode-数据结构-53.最大子数组和相关推荐

  1. leetcode系列-53.最大子数组和

    题目描述: 给你一个整数数组 nums ,请你找出一个具有最大和的连续子数组(子数组最少包含一个元素), 返回其最大和.子数组 是数组中的一个连续部分. 示例 1: 输入:nums = [-2,1,- ...

  2. LeetCode 53. 最大子数组和【贪心算法、动态规划】

    53. 最大子数组和 给你一个整数数组 nums ,请你找出一个具有最大和的连续子数组(子数组最少包含一个元素),返回其最大和. 子数组 是数组中的一个连续部分. 示例 1: 输入:nums = [- ...

  3. 53. 最大子数组和 392.判断子序列 115.不同的子序列

    53. 最大子数组和 dp[i]: 0-i-1,包含下标i-1的最大和为dp[i] 若dp[i-1]小于0,则和重新从nums[i]开始计算. 最后返回dp[i]最大值即可 392.判断子序列 i为短 ...

  4. [LeetCode] Maximum Subarray 最大子数组

    Find the contiguous subarray within an array (containing at least one number) which has the largest ...

  5. 【LeetCode-中等】53. 最大子数组和(详解)

    题目 给你一个整数数组 nums ,请你找出一个具有最大和的连续子数组(子数组最少包含一个元素),返回其最大和. 子数组 是数组中的一个连续部分. 方法1:动态规划1 作者:guanpengchn 链 ...

  6. 114. Leetcode 53. 最大子数组和 (动态规划-子序列问题)

    步骤一.确定状态: 确定dp数组及下标含义 dp[i]:包括下标i之前的最大连续子序列和为dp[i]. 步骤二.推断状态方程: dp[i]只有两个方向可以推出来: dp[i - 1] + nums[i ...

  7. 156. Leetcode 53. 最大子数组和 (贪心算法-进阶题目)

    class Solution:def maxSubArray(self, nums: List[int]) -> int:result = -float('inf')count = 0for i ...

  8. 【LeetCode】53.最大子序和

    题目 给定一个整数数组 nums,找到一个具有最大和的连续子数组(子数组最少包含一个元素),返回其最大和. 题解 方法1:暴力法 算法 暴力地用两重循环遍历所有情况 代码 class Solution ...

  9. LeetCode 题 - 53. 最大子序和 python解法

    题目 给定一个整数数组 nums ,找到一个具有最大和的连续子数组(子数组最少包含一个元素),返回其最大和. 示例: 输入: [-2,1,-3,4,-1,2,1,-5,4], 输出: 6 解释: 连续 ...

  10. leetcode之53.最大子序和

    题目详情 给定一个整数数组 nums ,找到一个具有最大和的连续子数组(子数组最少包含一个元素),返回其最大和. 示例: 输入: [-2,1,-3,4,-1,2,1,-5,4], 输出: 6 解释: ...

最新文章

  1. 测序数据学习笔记:bcl2fastq 安装
  2. 保守的机器学习如何拯救日新月异的我们
  3. 多维分析中的 UV 与 PV
  4. 修改ie9默认的quirk模式
  5. C++ 内存基本构件new/delete的意义、运用方式以及重载方式
  6. linux查看分区访问权限,linux查看分区是否开启acl权限
  7. 深入理解JAVA虚拟机——个人阅读笔记
  8. BAT面试问题--算法工程师(机器学习)
  9. 数据库原理mysql_数据库原理:MySql的安装
  10. Sublime Text 无法安装插件
  11. 上班时间应该包含交通时间
  12. Spring源码之bean的初始化initializeBean方法解读
  13. PS——证件照换底色的极简方法
  14. 源码解析kafka删除topic
  15. k8s - service
  16. Windows10切换用户显示User Profile Service或ProfSvc服务登录失败
  17. gitee搭建个人博客教程
  18. Android逆向之旅---动态方式破解apk进阶篇(IDA调试so源码)
  19. 励志: 我们来看看那些优秀的人的眼界和思想
  20. 第一章:电商及商品系统概述

热门文章

  1. layui框架学习(13:辅助元素)
  2. skynet:fork
  3. 西门子S7-1200PLC和KTP700触摸屏通过USS协议控制MM420变频器
  4. 《GEB-EGB》-人工智能
  5. Python使用pypinyin实现中文拼音转换教程
  6. 最低仅需万元到手,Gooxi AMD Rome平台服务器特价啦
  7. Python-property
  8. Oracle表空间已满解决方案
  9. display-table制作表格
  10. 表格某列实现动态隐藏展示