LeetCode中二叉树相关题
Leetcode中二叉树相关题
二叉树相关的题相对来说还是比较简单的,都是套路
第一题
:求二叉树中最大路径和
给定一个非空二叉树,返回其最大路径和。
本题中,路径被定义为一条从树中任意节点出发,达到任意节点的序列。该路径至少包含一个节点,且不一定经过根节点。
示例 1:
输入: [1,2,3]
1
/ \
2 3
输出: 6
示例 2:
输入: [-10,9,20,null,null,15,7]
-10
/ \
9 20
/ \
15 7
输出: 42
这就是个后序遍历嘛
int ans = INT_MIN;
int oneSideMax(TreeNode* root) {
if (root == nullptr) return 0;
int left = max(0, oneSideMax(root->left));
int right = max(0, oneSideMax(root->right));
ans = max(ans, left + right + root->val);
return max(left, right) + root->val;
}
C++代码:
/**
* Definition for a binary tree node.
* struct TreeNode {
* int val;
* TreeNode *left;
* TreeNode *right;
* TreeNode(int x) : val(x), left(NULL), right(NULL) {}
* };
*/
class Solution {
public:
int sum = INT_MIN;
int maxPathSumchild(TreeNode* root)
{
//递归出口
if(root == nullptr)
{
return 0;
}
//递归求 某个节点 的 左子树 和 右子树 的权值
int left = max(0,maxPathSumchild(root->left));
int right = max(0,maxPathSumchild(root->right));
//检查是否需要更新创建新的路径,新路径的权值是left + right + root->val,最后更新sum
sum = max(sum,(left + right + root->val));
//递归返回 到当前节点的一条最大路径
return max(left,right) + root->val;
}
int maxPathSum(TreeNode* root)
{
maxPathSumchild(root);
return sum;
}
};
第二题
:根据前序遍历和中序遍历的结果还原⼀棵⼆叉树
输入某二叉树的前序遍历和中序遍历的结果,请重建该二叉树。假设输入的前序遍历和中序遍历的结果中都不含重复的数字。
例如,给出
前序遍历 preorder = [3,9,20,15,7]
中序遍历 inorder = [9,3,15,20,7]
返回如下的二叉树:
3
/ \
9 20
/ \
15 7
限制:
- 0 <= 节点个数 <= 5000
直接看代码:
TreeNode buildTree(int[] preorder, int preStart, int preEnd,int[] inorder, int inStart, int inEnd, Map<Integer, Integer> inMap) {
if(preStart > preEnd || inStart > inEnd)
return null;
TreeNode root = new TreeNode(preorder[preStart]);
int inRoot = inMap.get(root.val);
int numsLeft = inRoot - inStart;
root.left = buildTree(preorder, preStart + 1, preStart + numsLeft,
inorder, inStart, inRoot - 1, inMap);
root.right = buildTree(preorder, preStart + numsLeft + 1, preEnd,
inorder, inRoot + 1, inEnd, inMap);
return root;
}
这道题不难,看上一个例子就知道基本思想,重点是边界控制问题
根据下面9张图看一下例子当中二叉树的构建过程
2.
3.
4.
5.
6.
7.
8.
9.
C++代码:
/**
* Definition for a binary tree node.
* struct TreeNode {
* int val;
* TreeNode *left;
* TreeNode *right;
* TreeNode(int x) : val(x), left(NULL), right(NULL) {}
* };
*/
class Solution {
public:
TreeNode* buildTree(vector<int>& preorder, vector<int>& inorder)
{
//递归分治
//控制好边界,剩下的交给递归
return recursionBuild(preorder.begin(),preorder.end(),
inorder.begin(),inorder.end());
}
//递归分治
TreeNode* recursionBuild(vector<int>::iterator preBegin, vector<int>::iterator preEnd, vector<int>::iterator inBegin, vector<int>::iterator inEnd )
{
if(inEnd==inBegin)
return NULL;
TreeNode* cur = new TreeNode(*preBegin);
//在中序遍历数组中找前序遍历的第一个节点,最为中序数组的左右子树分界点
auto root = find(inBegin,inEnd,*preBegin);
//递归构造左右子树
cur->left = recursionBuild(preBegin + 1,preBegin + (root - inBegin) + 1,
inBegin,root);
cur->right = recursionBuild(preBegin + 1 + (root - inBegin),preEnd,
root + 1,inEnd);
return cur;
}
};
第三题
:恢复⼀棵 BST
二叉搜索树中的两个节点
被错误地交换。
请在不改变其结构的情况下,恢复这棵树。
示例 1:
输入: [1,3,null,null,2]
1
/
3
\
2
输出: [3,1,null,null,2]
3
/
1
\
2
示例 2:
输入: [3,1,4,null,null,2]
3
/ \
1 4
/
2
输出: [2,1,4,null,null,3]
2
/ \
1 4
/
3
这道题难点,是找到那两个交换节点,把它交换过来
就行了.
这里我们二叉树搜索树的中序遍历
(中序遍历遍历元素是递增的)
如下图所示, 中序遍历顺序是 4,2,3,1,我们只要找到节点4和节点1交换顺序
即可!
这里我们有个规律发现这两个节点:
第一个节点,是第一个按照中序遍历时候前一个节点大于后一个节点,我们选取前一个节点,这里指节点4;
第二个节点,是在第一个节点找到之后, 后面出现前一个节点大于后一个节点,我们选择后一个节点,这里指节点1;
void traverse(TreeNode* node) {
if (!node) return;
traverse(node->left);
if (node->val < prev->val) {
s = (s == NULL) ? prev : s;
t = node;
}
prev = node;
traverse(node->right);
}
first记录第一个被错误交换的节点指针
,second记录第二个被错误交换的节点指针
,prev记录在中序遍历中上一个被遍历到的节点指针
;
通过比较当前节点的值和上一个节点的值来判断其是否是first或者second
;注意:若被错误交换的两个节点在中序遍历中是相邻的两个节点
(相邻是指以相邻的顺序被遍历到),与不相邻的区别
;
完整代码:
class Solution {
private:
TreeNode* first = nullptr;//指向第一个错误的节点
TreeNode* second = nullptr;//指向第二个错误的节点
TreeNode* pre = new TreeNode(INT_MIN);//相对于当前节点在中序遍历下的上一个节点
void helper(TreeNode* root)
{
if(root == nullptr)
{
return;
}
//中序遍历
helper(root->left);
//注意全程只有两个错误节点,所以下面的代码才可以那样写
//找到第一个节点才可以继续找第二个错误节点,但是注意这两个节点并不一定是相邻的
if(first == nullptr && pre->val > root->val)
{
first = pre;
}
if(first != nullptr && pre->val > root->val)
{
second = root;
}
pre = root;
helper(root->right);
}
public:
void recoverTree(TreeNode* root)
{
helper(root);
swap(first->val,second->val);
}
};
最后发现这不就是个中序遍历
嘛,
你看, Hard 难度的题⽬不过如此, ⽽且还这么有规律可循, 只要把框架写出来, 然后往相应的位置加东⻄就⾏了, 这不就是思路吗
上一篇: Leetcode - 最小栈
下一篇: 数据结构——计算二叉树中二分结点的个数
推荐阅读
-
【leetcode 简单】第十八题 删除排序链表中的重复元素
-
二叉树(LeetCode) C++相关知识代码 系列1
-
【每日一道算法题】Leetcode之longest-increasing-path-in-a-matrix矩阵中的最长递增路径问题 Java dfs+记忆化
-
C++实现LeetCode(105.由先序和中序遍历建立二叉树)
-
如何在Intellij中安装LeetCode刷题插件方便Java刷题
-
LeetCode算法题(数组相关)(二)——两数之和
-
Leetcode中等题-两两交换链表中的结点
-
LeetCode第958题 二叉树的完全性检验
-
leetcode 第 958 题:二叉树的完全性检验(C++)
-
判断一棵树是否是完全二叉树和求二叉树中两个节点的最近公共祖先——题集(十三)