LeetCode第[53]题(Java):Maximum Subarray
Posted 清风吹斜阳
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了LeetCode第[53]题(Java):Maximum Subarray相关的知识,希望对你有一定的参考价值。
题目:和最大的子序列
难度:Medium
题目内容:
Given an integer array nums
, find the contiguous subarray (containing at least one number) which has the largest sum and return its sum.
翻译:
给定一个整数数组nums,找到相邻的子数组(至少包含一个数字),它的总和是最大的,并返回它的和。
Example:
Input: [-2,1,-3,4,-1,2,1,-5,4], Output: 6 Explanation: [4,-1,2,1] has the largest sum = 6.
Follow up:
If you have figured out the O(n) solution, try coding another solution using the divide and conquer approach, which is more subtle.
我的思路:呃,没啥好思路,只会硬刚两个for,遍历所有子序列。。
我的代码:
1 public int maxSubArray(int[] nums) { 2 int max = nums[0]; 3 for (int i = 0; i < nums.length; i++) { 4 int sum = 0; 5 for (int j = i; j < nums.length; j++) { 6 sum += nums[j]; 7 max = sum > max ? sum : max; 8 } 9 } 10 return max; 11 }
我的复杂度:O(n2)
编码过程中的问题:(简单地代码有时候问题也是挺多的,可见并不能偷懒,想到方法了即使很简单也要动手写才行)
1、一开始取max 的初值为 0,然后发现当只有一个负数的时候会返回0,所以遍历取最值的时候,max或者min的初值应该取数组内部的值;
2、一开始sum的初值取的是 nums[i], j 从 i + 1 开始,然后发现最后一个元素(也是一个子序列)不会进入判断,所以遍历所有子序列的时候 j 应该是从 i 开始,sum的初值取0;
答案代码:
1 public int maxSubArray(int[] nums) { 2 int n = nums.length; 3 int[] dp = new int[n]; 4 dp[0] = nums[0]; 5 int max = dp[0]; 6 7 for(int i = 1; i < n; i++){ 8 dp[i] = Math.max(dp[i-1] + nums[i], nums[i]); 9 max = Math.max(max, dp[i]); 10 } 11 12 return max; 13 }
答案复杂度:O(N)
答案思路:采用动态规划的思想,新建一个数组,用它来记录以 nums[i] 结尾的序列能达到的最大值。
取 nums[i] 与 nums[i] + dp[i-1]的最大值就行(dp[i-1]如果大于零,则直接加,否则取nums[i]即为最大)
【注意并不是说dp[i]就表示以nums[i]结尾的序列内子序列能达到的最大值】
所以 dp[] 里面最大的那一个值就是要求的最大的。
优化:
因为只要知道dp的最大值即可,所以不需要把dp新建出来,只要用一个变量mem记录当前的,然后看是否比max大即可:
1 public int maxSubArray(int[] nums) { 2 int max = nums[0]; 3 int mem = max; 4 for (int i = 1; i < nums.length; i++) { 5 mem = Math.max(mem + nums[i], nums[i]); 6 max = Math.max(mem, max); 7 } 8 return max; 9 }
扩展:如果我还想知道那个最大子序列的终始位置呢?
1 public int[] maxSubArray(int[] nums) { 2 int n = nums.length; 3 int[][] dp = new int[n][2]; 4 dp[0][0] = nums[0]; 5 int[] max = {dp[0][0], 0, 0}; 6 7 for(int i = 1; i < n; i++){ 8 if (dp[i - 1][0] < 0) { 9 dp[i][0] = nums[i]; 10 dp[i][1] = i; 11 } else { 12 dp[i][0] = nums[i] + dp[i-1][0]; 13 dp[i][1] = dp[i-1][1]; 14 } 15 16 if (max[0] < dp[i][0]) { 17 max[0] = dp[i][0]; 18 max[1] = dp[i][1]; 19 max[2] = i; 20 } 21 } 22 23 return max; 24 }
算法复杂度:O(N)
max[] 三个元素分别是 max值、起始位置、终止位置
dp的下标就是终止位置了,所以再给dp加一个维度记录此终止位置对应的起始位置 dp[][]
【注意dp[i][1]的值也要根据 dp[i - 1][0] < 0 的判断而变化】
以上是关于LeetCode第[53]题(Java):Maximum Subarray的主要内容,如果未能解决你的问题,请参考以下文章
精选力扣500题 第53题 LeetCode 19. 删除链表的倒数第 N 个结点c++/java详细题解
算法千题案例⚡️每日LeetCode打卡⚡️——53.两个数组的交集 II