题目7:1026. 节点与其祖先之间的最大差值
同类题目
无
前置知识
- 无
题目描述
给定二叉树的根节点 root,找出存在于 不同 节点 A 和 B 之间的最大值 V,其中 V = |A.val - B.val|,且 A 是 B 的祖先。
(如果 A 的任何子节点之一为 B,或者 A 的任何子节点是 B 的祖先,那么我们认为 A 是 B 的祖先)
示例 1:
输入:root = [8,3,10,1,6,null,14,null,null,4,7,13]
输出:7
解释:
我们有大量的节点与其祖先的差值,其中一些如下:
|8 - 3| = 5
|3 - 7| = 4
|8 - 1| = 7
|10 - 13| = 3
在所有可能的差值中,最大值 7 由 |8 - 1| = 7 得出。
示例 2:
输入:root = [1,null,2,null,0,3]
输出:3
提示:
- 树中的节点数在
2到5000之间。 0 <= Node.val <= 105
思路分析
递归每个节点,计算遍历到当前节点时的最大值、最小值及最大差值。计算过程可以从根节点到叶子节点,也可以从叶子节点到根节点。
- 从根节点到叶子节点求每条路上的最大值与最小值,并使用局部变量记录每一次的最大值与最小值,往下传递最大值和最小值。
- 从叶子节点到根节点求每条路上的最大值与最小值,并使用局部变量记录每一次的最大值与最小值,往上传递最大值和最小值。
程序代码
第一种方法:从根节点到叶子节点
//https://leetcode.cn/problems/maximum-difference-between-node-and-ancestor/description/
//1026. 节点与其祖先之间的最大差值
class Solution {
public:
// 从根就开始传递最大值和最小值,使用mi 和 ma计录最小值和最大值
// 往下递归的过程中和经过的节点进行比较
int dfs(TreeNode *root, int mi, int ma) {
if (root == nullptr) {
return 0;
}
// abs(当前值 - 最小值) 和 abs(当前值 - 最大值) 选择差值最大的
int diff = max(abs(root->val - mi), abs(root->val - ma));
mi = min(mi, root->val);
ma = max(ma, root->val);
// 递归左右
diff = max(diff, dfs(root->left, mi, ma));
diff = max(diff, dfs(root->right, mi, ma));
return diff;
}
int maxAncestorDiff(TreeNode* root) {
return dfs(root, root->val, root->val);
}
};
复杂度分析:
时间复杂度: O(N) 其中N为二叉树的节点数量。
空间复杂度: O(N) 最差情况下(二叉树退化为链表)。
代码优化
一条从根出发向下的路径,我们要计算的实际上是这条路径上任意两点的最大差值,递归到空节点时完整走完了这一条从根到叶子的路径。在递归的过程中,我们记录该路径上面的最大值和最小值,走完整个路径的时(叶子节点)再计算差值。
//https://leetcode.cn/problems/maximum-difference-between-node-and-ancestor/description/
//1026. 节点与其祖先之间的最大差值
class Solution {
private:
int diff = 0;
public:
// 从根就开始传递最大值和最小值,使用mi 和 ma计录最小值和最大值
// 往下递归的过程中和经过的节点进行比较
void dfs(TreeNode *root, int mi, int ma) {
if (root == nullptr) {
// 叶子节点计算最大差值
diff = max(diff,ma - mi);
return;
}
// abs(当前值 - 最小值) 和 abs(当前值 - 最大值) 选择差值最大的
mi = min(mi, root->val);
ma = max(ma, root->val);
// 递归左右
dfs(root->left, mi, ma);
dfs(root->right, mi, ma);
}
int maxAncestorDiff(TreeNode* root) {
dfs(root, root->val, root->val);
return diff;
}
};
复杂度分析:
时间复杂度: O(N) 其中N为二叉树的节点数量,优化的是常数时间。
程序代码
第二种方法:从叶子节点到根节点
//https://leetcode.cn/problems/maximum-difference-between-node-and-ancestor/description/
//1026. 节点与其祖先之间的最大差值
class Solution {
private:
// 记录最大差值
int mx = 0;
public:
vector<int> travel(TreeNode* root)
{
// 记录返回值,num[0]为最大值,num[1]为最小值
vector<int> num;
if(root == nullptr)
{
num.push_back(-1);
num.push_back(0x3f3f3f3f);
return num;
}
vector<int> left = travel(root->left);
vector<int> right =travel(root->right);
// 返回的最大值、最小值和当前节点比较
int mxnum = max(root->val,max(left[0],right[0]));
int minnum = min(root->val,min(left[1],right[1]));
// 获取反馈后的最大差值
mx = max(max(root->val - minnum,mxnum - root->val),mx);
// 将该树作为子树反馈到上一层
num.push_back(mxnum);
num.push_back(minnum);
return num;
}
int maxAncestorDiff(TreeNode* root) {
travel(root);
return mx;
}
};
复杂度分析:
时间复杂度: O(N) 其中N为二叉树的节点数量。
空间复杂度: O(N) 最差情况下(二叉树退化为链表)。
题目感悟
二叉树可以从上往下传值,也可以从下往上返回值。从下往上比较繁琐。