7.4 二刷二叉树+图论

This commit is contained in:
zhangsan 2025-07-04 18:35:30 +08:00
parent f4e0ac9f81
commit a5d2dc48af
5 changed files with 100 additions and 23 deletions

View File

@ -9,7 +9,7 @@ package graph;
* 链接https://leetcode.cn/problems/number-of-islands/
*/
//二刷会做
public class NumIslands {
void dfs(char[][] grid, int r, int c) {
int nr = grid.length;

View File

@ -16,6 +16,7 @@ import java.util.Queue;
*/
//思想会代码写不利索
//二刷会
public class OrangesRotting {
public int orangesRotting(int[][] grid) {
int rows = grid.length;

View File

@ -2,6 +2,8 @@ package tree;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
/**
* 题目 236. 二叉树的最近公共祖先 (lowestCommonAncestor)
@ -12,36 +14,64 @@ import java.util.HashSet;
* 链接https://leetcode.cn/problems/lowest-common-ancestor-of-a-binary-tree/
*/
//二刷不会很妙的题
public class LowestCommonAncestor {
void helper(HashMap<TreeNode, TreeNode> map, TreeNode father, TreeNode cur) {
if (cur == null)
/**
* 先序遍历整棵树把每个节点的父节点记录到 map
* key = 当前节点
* value = 它的父节点根节点对应 null
*
* @param parentMap 存放节点到其父节点的映射
* @param parent 当前节点的父节点
* @param node 要处理的当前节点
*/
private void buildParentMap(Map<TreeNode, TreeNode> parentMap, TreeNode parent, TreeNode node) {
if (node == null) {
return;
map.put(cur, father);
helper(map, cur, cur.left);
helper(map, cur, cur.right);
}
// 记录当前节点的父节点
parentMap.put(node, parent);
// 递归处理左右子树
buildParentMap(parentMap, node, node.left);
buildParentMap(parentMap, node, node.right);
}
/**
* 返回二叉树中节点 p q 的最近公共祖先
*
* @param root 根节点
* @param p 第一个目标节点
* @param q 第二个目标节点
* @return 最近公共祖先节点
*/
public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) {
HashMap<TreeNode, TreeNode> map = new HashMap<>();
HashSet<TreeNode> set = new HashSet<>();
map.put(root, null);
helper(map, root, root.left);
helper(map, root, root.right);
// 1. 构建 parentMap每个节点指向它的父节点
Map<TreeNode, TreeNode> parentMap = new HashMap<>();
parentMap.put(root, null); // 根节点没有父节点
buildParentMap(parentMap, root, root.left);
buildParentMap(parentMap, root, root.right);
// p 以及其所有祖先加入 set
TreeNode tp = p;
while (tp != null) {
set.add(tp);
tp = map.get(tp);
// 2. p 自身以及它所有的祖先都放到一个 set
Set<TreeNode> ancestorsOfP = new HashSet<>();
TreeNode cur = p;
while (cur != null) {
ancestorsOfP.add(cur);
cur = parentMap.get(cur); // 一步步往上找父节点
}
// q 开始找到第一个出现在 p 祖先链中的节点
tp = q;
while (tp != null) {
if (set.contains(tp))
return tp;
tp = map.get(tp);
// 3. q 开始往上找到第一个在 ancestorsOfP 中出现的节点
cur = q;
while (cur != null) {
if (ancestorsOfP.contains(cur)) {
// 第一次相遇的节点就是最近公共祖先
return cur;
}
cur = parentMap.get(cur);
}
return null; // 理论上不可能执行到这里因为肯定存在公共祖先
// 理论上不会执行到这里因为二叉树必定存在公共祖先
return null;
}
}

View File

@ -0,0 +1,45 @@
package tree;
/**
* 题目 124. 二叉树中的最大路径和 (maxPathSum)
* 描述二叉树中的 路径 被定义为一条节点序列序列中每对相邻节点之间都存在一条边同一个节点在一条路径序列中 至多出现一次 该路径 至少包含一个 节点且不一定经过根节点
* 路径和 是路径中各节点值的总和
* 给你一个二叉树的根节点 root 返回其 最大路径和
* 链接https://leetcode.cn/problems/binary-tree-maximum-path-sum/
*/
//二刷不会
public class MaxPathSum {
/**
* 计算当前节点的 最大路径和 可以包含左右节点但最大贡献度不能同时包括左右节点因为对于某节点他的贡献只能带其中一个孩子带大孩子走整个路径才能向上延伸
* priceNewpath = node.val + leftGain + rightGain把当前节点当作拐点将左右子树的最大非负贡献都连上再加上自身得到一条完整过顶路径的和用它更新全局最大值
* return node.val + Math.max(leftGain, rightGain)向上只传递一条最优子路径的贡献自身 + 较大子贡献因为合法路径不能同时分叉到左右两边
*/
int maxSum = Integer.MIN_VALUE;
public int maxPathSum(TreeNode root) {
maxGain(root);
return maxSum;
}
public int maxGain(TreeNode node) {
if (node == null) {
return 0;
}
// 递归计算左右子节点的最大贡献值
// 只有在最大贡献值大于 0 才会选取对应子节点
int leftGain = Math.max(maxGain(node.left), 0);
int rightGain = Math.max(maxGain(node.right), 0);
// 节点的最大路径和取决于该节点的值与该节点的左右子节点的最大贡献值
int priceNewpath = node.val + leftGain + rightGain;
// 更新答案
maxSum = Math.max(maxSum, priceNewpath);
// 返回节点的最大贡献值
return node.val + Math.max(leftGain, rightGain);
}
}

View File

@ -14,6 +14,7 @@ import java.util.Map;
//前缀和想到了代码不会写
//二刷不会
public class PathSum {
/**
* prefix 这张哈希表只应该保存当前递归栈从根结点到正在访问的那个结点这条路径上出现过的前缀和!!!!
* 当递归函数从一个结点返回到它的父结点时这个结点及其子树已经遍历完毕它对应的前缀和在后面的兄弟子树中就再也不会出现在