题目汇总:https://leetcode-cn.com/tag/tree/
105. 从前序与中序遍历序列构造二叉树中等[✔]
106. 从中序与后序遍历序列构造二叉树中等[✔]
107. 二叉树的层次遍历 II简单[✔]
108. 将有序数组转换为二叉搜索树简单[✔]
110. 平衡二叉树简单[✔]
111. 二叉树的最小深度简单[✔]
112. 路径总和简单[✔]
113. 路径总和 II中等
114. 二叉树展开为链表中等[✔]
116. 填充每个节点的下一个右侧节点指针中等[✔]
105. 从前序与中序遍历序列构造二叉树中等
根据一棵树的前序遍历与中序遍历构造二叉树。
注意:
你可以假设树中没有重复的元素。
例如,给出
前序遍历 preorder = [3,9,20,15,7]
中序遍历 inorder = [9,3,15,20,7]
返回如下的二叉树:[3,9,20,null,null,15,7]
思路:递归
根据中序遍历和前序遍历可以确定二叉树,具体过程为:
根据前序序列第一个结点确定根结点
根据根结点在中序序列中的位置分割出左右两个子序列
对左子树和右子树分别递归使用同样的方法继续分解
/**
* Definition for a binary tree node.
* public class TreeNode {
* int val;
* TreeNode left;
* TreeNode right;
* TreeNode(int x) { val = x; }
* }
*/
class Solution {
public TreeNode buildTree(int[] preorder, int[] inorder) {//执行用时 :13 ms, 在所有 Java 提交中击败了21.30%的用户
if(preorder.length==0||inorder.length==0)
return null;
TreeNode root = new TreeNode(preorder[0]);//根据前序遍历确定根节点
int len = preorder.length;
for(int i=0;i
106. 从中序与后序遍历序列构造二叉树中等
根据一棵树的中序遍历与后序遍历构造二叉树。
注意:
你可以假设树中没有重复的元素。
例如,给出中序遍历 inorder = [9,3,15,20,7],后序遍历 postorder = [9,15,7,20,3]
返回如下的二叉树:[3,9,20,null,null,15,7]
思路:递归
根据中序遍历和后序遍历可以确定二叉树,具体过程为:
根据后序序列最后一个结点确定根结点
根据根结点在中序序列中的位置分割出左右两个子序列
对左子树和右子树分别递归使用同样的方法继续分解
/**
* Definition for a binary tree node.
* public class TreeNode {
* int val;
* TreeNode left;
* TreeNode right;
* TreeNode(int x) { val = x; }
* }
*/
class Solution {
public TreeNode buildTree(int[] inorder, int[] postorder) {//执行用时 :13 ms, 在所有 Java 提交中击败了17.65%的用户
if(inorder.length == 0 || postorder.length == 0)
return null;
TreeNode root = new TreeNode(postorder[postorder.length-1]);
for(int i=0;i
107. 二叉树的层次遍历 II简单
给定一个二叉树,返回其节点值自底向上的层次遍历。 (即按从叶子节点所在层到根节点所在的层,逐层从左向右遍历)
例如:给定二叉树[3,9,20,null,null,15,7]
,
返回其自底向上的层次遍历为:
思路:迭代
/**
* Definition for a binary tree node.
* public class TreeNode {
* int val;
* TreeNode left;
* TreeNode right;
* TreeNode(int x) { val = x; }
* }
*/
class Solution {//执行用时 :1 ms, 在所有 Java 提交中击败了98.82%的用户
public List> levelOrderBottom(TreeNode root) {
LinkedList> res = new LinkedList<>();
Queue queue = new ArrayDeque<>();
if(root != null){
queue.add(root);//将根节点放入队列中,然后不断遍历队列
}
while(!queue.isEmpty()){
int n = queue.size();//获取当前队列的长度,也就是当前这一层的节点个数
List level = new ArrayList<>();
for(int i=0;i
108. 将有序数组转换为二叉搜索树简单
将一个按照升序排列的有序数组,转换为一棵高度平衡二叉搜索树。
本题中,一个高度平衡二叉树是指一个二叉树*每个节点 *的左右两个子树的高度差的绝对值不超过 1。
示例:
给定有序数组:[-10,-3,0,5,9]
一个可能的答案是:[0,-3,9,-10,null,5],它表示下面这个高度平衡二叉搜索树。
思路:递归
因为是一个按照升序排列的有序数组,转换成平衡二叉树,那么把根节点选为数组的中点即可,找到根节点,然后把数组一分为二成为左子树和右子树,进入递归即可。
/**
* Definition for a binary tree node.
* public class TreeNode {
* int val;
* TreeNode left;
* TreeNode right;
* TreeNode(int x) { val = x; }
* }
*/
class Solution {
public TreeNode sortedArrayToBST(int[] nums) {//执行用时 :0 ms, 在所有 Java 提交中击败了100.00%的用户
return buildTree(nums, 0, nums.length-1);
}
private TreeNode buildTree(int[] nums, int left, int right) {
if (left > right) {
return null;
}
//当构造节点的左右子树时,对递增数组进行拆分并进行递归调用
int mid = left + (right - left + 1) / 2;
TreeNode root = new TreeNode(nums[mid]);
root.left = buildTree(nums, left, mid - 1);
root.right = buildTree(nums, mid + 1, right);
return root;
}
}
110. 平衡二叉树简单
给定一个二叉树,判断它是否是高度平衡的二叉树。
本题中,一棵高度平衡二叉树定义为:
一个二叉树每个节点的左右两个子树的高度差的绝对值不超过1。
示例 :
给定二叉树[3,9,20,null,null,15,7]
返回true
思路:递归
/**
* Definition for a binary tree node.
* public class TreeNode {
* int val;
* TreeNode left;
* TreeNode right;
* TreeNode(int x) { val = x; }
* }
*/
class Solution {
public boolean isBalanced(TreeNode root) {//执行用时 :1 ms, 在所有 Java 提交中击败了99.78%的用户
if(root == null)
return true;
if(Math.abs(Height(root.left) - Height(root.right)) > 1)
return false;
return isBalanced(root.left) && isBalanced(root.right);
}
public int Height(TreeNode root){
if(root == null)
return 0;
int leftHeight = Height(root.left) + 1;
int rightHeight = Height(root.right) + 1;
return leftHeight > rightHeight ? leftHeight : rightHeight;
}
}
111. 二叉树的最小深度简单
给定一个二叉树,找出其最小深度。
最小深度是从根节点到最近叶子节点的最短路径上的节点数量。
说明: 叶子节点是指没有子节点的节点。
示例:
给定二叉树[3,9,20,null,null,15,7]
,
返回它的最小深度 2.
思路:递归
按照 104. 二叉树的最大深度的思路来解题出错
看了题解之后https://leetcode-cn.com/problems/minimum-depth-of-binary-tree/solution/li-jie-zhe-dao-ti-de-jie-shu-tiao-jian-by-user7208/
/**
* Definition for a binary tree node.
* public class TreeNode {
* int val;
* TreeNode left;
* TreeNode right;
* TreeNode(int x) { val = x; }
* }
*/
/*叶子节点的定义是左孩子和右孩子都为 null 时叫做叶子节点
当 root 节点左右孩子都为空时,返回 1
当 root 节点左右孩子有一个为空时,返回不为空的孩子节点的深度
当 root 节点左右孩子都不为空时,返回左右孩子较小深度的节点值*/
class Solution {
public int minDepth(TreeNode root) {//执行用时 :0 ms, 在所有 Java 提交中击败了100.00%的用户
if(root == null)
return 0;
if(root.left == null && root.right == null)
return 1;
int leftDepth = minDepth(root.left);
int rightDepth = minDepth(root.right);
if(root.left == null || root.right == null){
return leftDepth + rightDepth + 1;
}
return Math.min(leftDepth, rightDepth)+1;
}
}
112. 路径总和简单
给定一个二叉树和一个目标和,判断该树中是否存在根节点到叶子节点的路径,这条路径上所有节点值相加等于目标和。
说明: 叶子节点是指没有子节点的节点。
示例:
给定如下二叉树,以及目标和sum = 22
,
返回true
, 因为存在目标和为 22 的根节点到叶子节点的路径5->4->11->2
。
思路:递归
/**
* Definition for a binary tree node.
* public class TreeNode {
* int val;
* TreeNode left;
* TreeNode right;
* TreeNode(int x) { val = x; }
* }
*/
class Solution {
public boolean hasPathSum(TreeNode root, int sum) {//执行用时 :0 ms, 在所有 Java 提交中击败了100.00%的用户
if(root == null)
return false;
if(root.left == null && root.right == null)
return sum - root.val == 0;
return hasPathSum(root.left, sum - root.val) || hasPathSum(root.right, sum - root.val);
}
}
113. 路径总和 II中等
给定一个二叉树和一个目标和,找到所有从根节点到叶子节点路径总和等于给定目标和的路径。
说明: 叶子节点是指没有子节点的节点。
示例:
给定如下二叉树,以及目标和sum = 22
,
返回:
[
[5,4,11,2],
[5,8,4,5]
]
思路:DFS+递归
/**
* Definition for a binary tree node.
* public class TreeNode {
* int val;
* TreeNode left;
* TreeNode right;
* TreeNode(int x) { val = x; }
* }
*/
class Solution {
public List> pathSum(TreeNode root, int sum) {//执行用时 :4 ms, 在所有 Java 提交中击败了14.93%的用户
List> res = new ArrayList<>();
if (root == null) {
return res;
}
// 从根结点到叶子结点的路径
List path = new ArrayList<>();
dfs(root, sum, path, res);
return res;
}
private void dfs(TreeNode root, int sum, List path, List> res) {
if (root == null) {
return;
}
path.add(root.val);
sum -= root.val;
if (root.left == null && root.right == null && sum == 0) {
res.add(path);
return;
}else{
dfs(root.left, sum, new ArrayList<>(path), res);
dfs(root.right, sum, new ArrayList<>(path), res);
}
}
}
114. 二叉树展开为链表中等
给定一个二叉树,原地将它展开为一个单链表。
例如,给定二叉树
将其展开为:
思路:递归+DFS
将左子树插入到右子树的地方
将原来的右子树接到左子树的最右边节点
考虑新的右子树的根节点,一直重复上边的过程,直到新的右子树为 null
/**
* Definition for a binary tree node.
* public class TreeNode {
* int val;
* TreeNode left;
* TreeNode right;
* TreeNode(int x) { val = x; }
* }
*/
class Solution {//执行用时 :0 ms, 在所有 Java 提交中击败了100.00%的用户
public void flatten(TreeNode root) {
if(root == null)
return;
//先把左右子树捋直
flatten(root.right);
flatten(root.left);
TreeNode temp = root.right;//把捋直的右子树备份一下
root.right = root.left;//把捋直的左子树放到右边
root.left = null;//把左子树置空
while(root.right != null){//找到现在右子树的最后一个结点
root = root.right;
}
root.right = temp;//把捋直的原来的右子树接上去
}
}
116. 填充每个节点的下一个右侧节点指针中等
给定一个完美二叉树,其所有叶子节点都在同一层,每个父节点都有两个子节点。二叉树定义如下:
struct Node {
int val;
Node *left;
Node *right;
Node *next;
}
填充它的每个 next 指针,让这个指针指向其下一个右侧节点。如果找不到下一个右侧节点,则将 next 指针设置为NULL
。
初始状态下,所有 next 指针都被设置为NULL
。
示例:
解释:给定二叉树如图 A 所示,你的函数应该填充它的每个 next 指针,以指向其下一个右侧节点,如图 B 所示。
提示
你只能使用常量级额外空间。
使用递归解题也符合要求,本题中递归程序占用的栈空间不算做额外的空间复杂度。
思路一:递归
左子树的next就是右子树,右子树的next就是next节点的左子树
/*
// Definition for a Node.
class Node {
public int val;
public Node left;
public Node right;
public Node next;
public Node() {}
public Node(int _val) {
val = _val;
}
public Node(int _val, Node _left, Node _right, Node _next) {
val = _val;
left = _left;
right = _right;
next = _next;
}
};
*/
class Solution {
public Node connect(Node root) //执行用时 :0 ms, 在所有 Java 提交中击败了100.00%
if(root == null || root.left == null)
return root;
root.left.next = root.right;//左子树的next就是右子树
if(root.next != null){
root.right.next = root.next.left;//右子树的next就是next节点的左子树
}
connect(root.left);
connect(root.right);
return root;
}
}
思路二:迭代
代码来自链接https://leetcode-cn.com/problems/populating-next-right-pointers-in-each-node/solution/dong-hua-yan-shi-san-chong-shi-xian-116-tian-chong/
class Solution {//执行用时:0 ms, 在所有 Java 提交中击败了100.00%的用户
public Node connect(Node root) {
if(root==null) {
return root;
}
Node pre = root;
//循环条件是当前节点的left不为空,当只有根节点
//或所有叶子节点都出串联完后循环就退出了
while(pre.left!=null) {
Node tmp = pre;
while(tmp!=null) {
//将tmp的左右节点都串联起来
//注:外层循环已经判断了当前节点的left不为空
tmp.left.next = tmp.right;
//下一个不为空说明上一层已经帮我们完成串联了
if(tmp.next!=null) {
tmp.right.next = tmp.next.left;
}
//继续右边遍历
tmp = tmp.next;
}
//从下一层的最左边开始遍历
pre = pre.left;
}
return root;
}
}