以下题目均整理自力扣,由易到难,掌握以下题目,基本对该类题型有一个深刻的理解;求解本类题目的基本套路是DFS
112.路径总和
class Solution {
boolean flag;
public boolean hasPathSum(TreeNode root, int targetSum) {
if(root==null) return false;
dfs(root,0,targetSum);
return flag;
}
void dfs(TreeNode root,int sum,int targetSum){
if(root.left==null && root.right==null){
flag |= (sum + root.val == targetSum);
return;
}
if(root.left!=null) dfs(root.left,sum+root.val,targetSum);
if(root.right!=null) dfs(root.right,sum+root.val,targetSum);
}
}
113.路径总和 II
class Solution {
// 前缀和
// 思路: 记录前缀和到一个map中,只要 preSum - targetSum目标值 在map中存在
// 就说明存在符合targetSum的路径
List<List<Integer>>ans = new ArrayList<>();
List<Integer> temp = new ArrayList<>();
public List<List<Integer>> pathSum(TreeNode root, int targetSum) {
if(root==null) return ans;
dfs(root,0,targetSum,new ArrayList<Integer>());
return ans;
}
// 整个过程temp都是引用同一个,所以在返回上一层的时候需要回溯
void dfs(TreeNode root,int sum,int targetSum,List<Integer>temp){
if(root.left==null && root.right==null){
if(sum + root.val == targetSum){
temp.add(root.val);
ans.add(new ArrayList<>(temp));
// 返回上一层的时候需要回溯
temp.remove(temp.size()-1);
}
return;
}
temp.add(root.val);
if(root.left!=null) dfs(root.left,sum+root.val,targetSum,temp);
if(root.right!=null) dfs(root.right,sum+root.val,targetSum,temp);
// 返回上一层的时候需要回溯!
temp.remove(temp.size()-1);
}
}
437.路径总和 III
这里用到map、前缀和来记录 路径和等于target的数量,这个解法真不容易想到、
如果 前缀和减去target得到的结果如果存在于map中,说明存在路径和为target的路径
参考题解: . - 力扣(LeetCode)
这个题还有个坑,后面有个case数很大,导致计算前缀和会发生溢出,影响到最终计算的结果,所以需要把Map的key换成Long类型,对应的case为:[1000000000,1000000000,null,294967296,null,1000000000,null,1000000000,null,1000000000]
class Solution {
int ans;
// k:前缀和 v: 存在该前缀和的数量
// 测试case中存在结点val值很大的情况,所以用Long类型
Map<Long,Integer> map = new HashMap<>();
public int pathSum(TreeNode root, int targetSum) {
// 前缀和为0需要特殊处理,否则如果存在前缀和为targetSum的
// 那么就会错失从根结点到当前结点的这条路径
map.put(0L,1);
dfs(root,targetSum,0);
return ans;
}
void dfs(TreeNode root,int targetSum,long preSum){
if(root==null) return;
preSum += root.val;
// 如果preSum-targetSum 在map中存在,表示存在和为target的路径
ans += map.getOrDefault(preSum-targetSum,0);
map.put(preSum,map.getOrDefault(preSum,0)+1);
dfs(root.left,targetSum,preSum);
dfs(root.right,targetSum,preSum);
// 返回上一层,就不包含该结点了,需要把经过该结点的前缀和-1
map.put(preSum,map.get(preSum)-1);
// 这里preSum不需要回溯
}
}
124.二叉树中的最大路径和
这题最多是mid,不是hard级别(不过太久了我又不会写了。。)
class Solution {
int max = Integer.MIN_VALUE;
public int maxPathSum(TreeNode root) {
if(root.left == null && root.right == null) return root.val;
dfs(root);
return max;
}
// 返回以当前结点为根结点的树的权重和
int dfs(TreeNode root) {
if (root == null) return 0;
// 左子树的和
int left = dfs(root.left);
// 右子树的和
int right = dfs(root.right);
max = Math.max(left+right+root.val, max);
// 如果以root结点得到的权重和为小于0,则不应该加上去
return Math.max(Math.max(left,right)+root.val,0);
}
}
这是一条路径:
这也是一条路径:
这个就不是一条路径
二叉树的最大路径和II
修改下路径的定义,从根节点往左或往右构成的路径,不能出现兄弟节点
public class T124_maxPathSumII {
@Test
public void test() {
Integer[] nums = new Integer[]{3, -2, 1, null, 4};
TreeNode root = TreeNode.buildTree(nums);
System.out.println(maxPathSum(root));
}
int max = Integer.MIN_VALUE;
public int maxPathSum(TreeNode root) {
dfs(root);
return max;
}
public int dfs(TreeNode root) {
if (root == null) return 0;
int left = dfs(root.left);
int right = dfs(root.right);
max = Math.max(Math.max(left, right) + root.val, max);
return Math.max(Math.max(left, right) + root.val, 0);
}
}