> 文章列表 > LeetCode 1026. Maximum Difference Between Node and Ancestor【DFS,BFS,树】中等

LeetCode 1026. Maximum Difference Between Node and Ancestor【DFS,BFS,树】中等

LeetCode 1026. Maximum Difference Between Node and Ancestor【DFS,BFS,树】中等

本文属于「征服LeetCode」系列文章之一,这一系列正式开始于2021/08/12。由于LeetCode上部分题目有锁,本系列将至少持续到刷完所有无锁题之日为止;由于LeetCode还在不断地创建新题,本系列的终止日期可能是永远。在这一系列刷题文章中,我不仅会讲解多种解题思路及其优化,还会用多种编程语言实现题解,涉及到通用解法时更将归纳总结出相应的算法模板。

为了方便在PC上运行调试、分享代码文件,我还建立了相关的仓库:https://github.com/memcpy0/LeetCode-Conquest。在这一仓库中,你不仅可以看到LeetCode原题链接、题解代码、题解文章链接、同类题目归纳、通用解法总结等,还可以看到原题出现频率和相关企业等重要信息。如果有其他优选题解,还可以一同分享给他人。

由于本系列文章的内容随时可能发生更新变动,欢迎关注和收藏征服LeetCode系列文章目录一文以作备忘。

Given the root of a binary tree, find the maximum value v for which there exist different nodes a and b where v = |a.val - b.val| and a is an ancestor of b.

A node a is an ancestor of b if either: any child of a is equal to b or any child of a is an ancestor of b.

Example 1:

Input: root = [8,3,10,1,6,null,14,null,null,4,7,13]
Output: 7
Explanation: We have various ancestor-node differences, some of which are given below :
|8 - 3| = 5
|3 - 7| = 4
|8 - 1| = 7
|10 - 13| = 3
Among all possible differences, the maximum value of 7 is obtained by |8 - 1| = 7.

Example 2:

Input: root = [1,null,2,null,0,3]
Output: 3

Constraints:

  • The number of nodes in the tree is in the range [2, 5000].
  • 0 <= Node.val <= 105

题意:给定二叉树的根节点 root,找出存在于 不同 节点 A 和 B 之间的最大值 V,其中 V = |A.val - B.val|,且 A 是 B 的祖先。如果 A 的任何子节点之一为 B,或者 A 的任何子节点是 B 的祖先,那么我们认为 A 是 B 的祖先。


解法 DFS自顶向下

如果节点 AAA 在从根节点到节点 BBB路径上,则称 AAABBB祖先节点,称 BBBAAA子孙节点。

注:在这个定义中,BBB 的祖先节点可以是 BBB 自己。例如示例 1 中 666 的祖先节点自上而下依次为 8,3,68,3,68,3,6
注:虽然题目要求「不同节点」,但计算的是最大差值,相同节点算出来的差值为 000 ,不影响最大差值。

对于题目给出的公式 V=∣A.val−B.val∣V = |A.\\textit{val} - B.\\textit{val}|V=A.valB.val ,为了让 VVV 尽量大,分类讨论:

  • 如果 A.val<B.valA.\\textit{val} < B.\\textit{val}A.val<B.val ,那么 A.valA.valA.val 越小,VVV 越大。
  • 如果 A.val≥B.valA.val≥B.valA.valB.val ,那么 A.valA.valA.val 越大,VVV 越大;

因此,无需记录递归路径中的全部节点值,只需要记录递归路径中的最小值 mnmnmn 和最大值 mxmxmx 。每递归到一个节点 BBB ,计算
max⁡(∣mn−B.val∣,∣mx−B.val∣)max⁡(∣mn−B.val∣,∣mx−B.val∣)max(mnB.val,mxB.val)
并更新答案的最大值。由于 mn≤B.val≤mx\\textit{mn}\\le B.\\textit{val} \\le \\textit{mx}mnB.valmx ,上式可化简为 max⁡(B.val−mn,mx−B.val)\\max(B.\\textit{val}-\\textit{mn},\\textit{mx}-B.\\textit{val})max(B.valmn,mxB.val)

class Solution {private int ans;public int maxAncestorDiff(TreeNode root) {dfs(root, root.val, root.val);return ans;}private void dfs(TreeNode node, int mn, int mx) {if (node == null) return;// 虽然题目要求「不同节点」,但相同节点的差值为 0,不会影响最大差值// 所以先更新 mn 和 mx,再计算差值也可以// 在这种情况下,一定满足 mn <= node.val <= mxmn = Math.min(mn, node.val);mx = Math.max(mx, node.val);ans = Math.max(ans, Math.max(node.val - mn, mx - node.val));dfs(node.left, mn, mx);dfs(node.right, mn, mx);}
}

换个角度看问题:对于一条从根出发向下的路径,我们要计算的实际上是这条路径上任意两点的最大差值。递归到叶子时,mx\\textit{mx}mx 是从根到叶子的路径上的最大值,mn\\textit{mn}mn 是从根到叶子的路径上的最小值,所以 mx−mn\\textit{mx}-\\textit{mn}mxmn 就是从根到叶子的路径上任意两点的最大差值。所以无需每个节点都去更新答案,而是在递归到终点时才去更新答案

class Solution {
private:int ans = 0;void dfs(TreeNode* r, int mx, int mn) {if (r == nullptr) {ans = max(mx - mn, ans);return;}mx = max(mx, r->val);mn = min(mn, r->val); dfs(r->left, mx, mn);dfs(r->right, mx, mn);}
public:int maxAncestorDiff(TreeNode* root) {dfs(root, root->val, root->val);return ans;}
};

复杂度分析:

  • 时间复杂度:O(n)O(n)O(n) ,其中 nnn 为二叉树的节点个数。
  • 空间复杂度:O(n)O(n)O(n) 。最坏情况下,二叉树退化成一条链,递归需要 O(n)O(n)O(n) 的栈空间。

解法2 DFS自底向上

法一的思路是维护 BBB 的祖先节点中的最小值和最大值,我们还可以站在 AAA 的视角,维护 AAA 的子孙节点中的最小值 mnmnmn 和最大值 mxmxmx 。换句话说,最小值和最大值不再作为入参,而是作为返回值,意思是以 AAA 为根的子树中的最小值和最大值。

递归到节点 AAA 时,初始化 mnmnmnmxmxmxA.valA.valA.val ,然后递归左右子树,拿到左右子树的最小值和最大值,去更新 mnmnmnmxmxmx ,然后计算
max⁡(∣mn−A.val∣,∣mx−A.val∣)\\max(|\\textit{mn}-A.\\textit{val}|,|\\textit{mx}-A.\\textit{val}|)max(mnA.val,mxA.val)
并更新答案的最大值。由于 mn≤A.val≤mx\\textit{mn}\\le A.\\textit{val} \\le \\textit{mx}mnA.valmx ,上式可化简为
max⁡(A.val−mn,mx−A.val)\\max(A.\\textit{val}-\\textit{mn},\\textit{mx}-A.\\textit{val})max(A.valmn,mxA.val)

class Solution {int ans = 0; pair<int, int> dfs(TreeNode *node) {if (node == nullptr)return {INT_MAX, INT_MIN}; // 保证空节点不影响 mn 和 mxint mn = node->val, mx = mn;auto [l_mn, l_mx] = dfs(node->left);auto [r_mn, r_mx] = dfs(node->right);mn = min(mn, min(l_mn, r_mn));mx = max(mx, max(l_mx, r_mx));ans = max(ans, max(node->val - mn, mx - node->val));return {mn, mx};} 
public:int maxAncestorDiff(TreeNode *root) {dfs(root);return ans;}
};

复杂度:

  • 时间复杂度:O(n)O(n)O(n) ,其中 nnn 为二叉树的节点个数。
  • 空间复杂度:O(n)O(n)O(n) 。最坏情况下,二叉树退化成一条链,递归需要 O(n)O(n)O(n) 的栈空间。