发现这两道题运用了同一个思路,把它们放到一起
Problem: Maximum SubArray
Find the contiguous subarray within an array (containing at least one number) which has the largest sum.
For example, given the array [−2,1,−3,4,−1,2,1,−5,4]
,
the contiguous subarray [4,−1,2,1]
has the largest sum = 6
.
分析:
我们这么想,当我们从头到尾遍历这个数组的时候,对于一个数组里的数字,它有几种选择呢?
它只有两种选择: 1. 加入之前的SubArray, 2. 自己另起一个SubArray
好,那什么时候会出现这两种情况呢。
注意我们是找累加的最大值,那么,
如果之前SubArray的总体和大于0的话,我们可以认为其对后续数字是有贡献的。这种情况下我们选择加入之前的SubArray
如果之前SubArray的总体和为0或者小于0的话,我们可以认为其对后续数字是没有贡献,甚至是有害的(小于0时)。这种情况下我们只能选择以这个数字开始,另起一个SubArray
明白了这点,代码就很好写了, sum记录之前SubArray的和,max用来返回最大值,当sum的值大于max时,说明发现和更大的SubArray序列,此时更新max的值。
public class Solution {
public int maxSubArray(int[] A) {
int max = Integer.MIN_VALUE;
int sum = 0;
for(int i=0; i<A.length; i++){
sum = sum>0? sum + A[i]: A[i];
max = Math.max(sum,max);
}
return max;
}
}
明白了这个题,再看Binary Tree Maximum Path Sum 就非常直观了
Problem: Binary Tree Maximum Path Sum
Given a binary tree, find the maximum path sum.
The path may start and end at any node in the tree.
For example:
Given the below binary tree,
1
/ \
2 3
Return 6
.
分析:
首先,我们应该注意到这个Path能从任意节点开始,到任意节点结束,不过不要被它吓住,仔细想想是不是和上面的题差不多
如果说Array只有一个方向的话,那么Binary Tree其实只是左,右两个方向而已,我们需要比较两个方向上的值
那好,如果说Array可以从头到尾遍历,那么Binary Tree怎么办呢,我们可以采用Binary Tree最常用的dfs来进行遍历
我们先上代码:
public class Solution { //代码是MITBBS里面Peking2二爷的思路
int max;
public int maxPathSum(TreeNode root) {
max = Integer.MIN_VALUE;
dfs(root);
return max;
}
public int dfs(TreeNode root){
if (root==null) return 0;
int l = dfs(root.left);
int r = dfs(root.right);
int sum = root.val;
if (l>0) sum += l;
if (r>0) sum += r;
max = Math.max(max,sum);
return Math.max(r,l)>0?Math.max(r,l)+root.val:root.val;
}
}
我们结合代码和下面这个图来进行说明
首先,L, R 是dfs返回的两个子分支的值我们先不提。对于sum,我们照搬第一题的思路
如果L大于0,那么对后续是有利的,我们加上L。 例如图中A节点,左子树大于0,那么更新最大路径的和为【B, A】的和
如果R大于0,那么对后续是有利的,我们加上R。例如图中A节点,右子树大于0,那么更新最大路径的和为【C, A】的和
如果L,R同时大于0,左右两边对后续都是有利的,我们两边都要,例如图中A节点,左右子树都大于0,那么更新最大路径的和为【B,A,C】的和
如果L,R都小于等于0,那么左右两边对后续都是无利甚至有害的,我们从这个节点,另起一个路径,例如图中的A节点,更新最大路径的和0为【A】的和
好了,sum怎么来的我们已经很清楚了,还有一点值得注意是在Return的语句里
return Math.max(r,l)>0?Math.max(r,l)+root.val:root.val;
可能有人疑惑了,为什么只返回一个方向的值呢?(如果Math.max(r,l)>0, 我们只返回这两个方向上最大值的方向)
我们需要明确sum 和 return 返回值的区别,还是举A节点的例子
对于sum,当我们两个方向的值都取得时候,路径是图中绿色笔的路径,是因为分析sum的时候我们是站在A节点的角度上分析的
而对于Return,A节点最后Return的时候,是返回到上一层D节点的递归中。重点是,Return方向是向上的。所以不会出现图中绿色的路径,只可能出现红色的两个路径中的一条(当Math.max(l,r)>0时)或者就一个D节点(当Math.max(l,r)<=0时)
这一点明确后,整个题就变得很直观了,最后记得持续更新max,当发现更大路径和的时候
这两个题放到一起,大家感受一下。