二叉树
- 1.导论
- 2.编程题
- 2.1 144.二叉树的前序遍历
- 2.2 94.二叉树的中序遍历
- 2.3 145.二叉树的后序遍历
- 2.4 102. 二叉树的层序遍历
- 2.5 107. 二叉树的层序遍历 II
- 2.6 199. 二叉树的右视图
- 2.7 637.二叉树的层平均值
- 2.8 429.N叉树的层序遍历
- 2.9 515.在每个树行中找最大值
- 2.10 116. 填充每个节点的下一个右侧节点指针
- 2.11 117. 填充每个节点的下一个右侧节点指针 II
- 2.12 104. 二叉树的最大深度
- 2.13 111. 二叉树的最小深度
- 2.14 226. 翻转二叉树
- 2.15 101. 对称二叉树
- 2.16 100. 相同的树
- 2.17 572. 另一棵树的子树
- 2.18 222. 完全二叉树的节点个数
- 2.19 110. 平衡二叉树
- 2.20 257. 二叉树的所有路径
- 2.21 404. 左叶子之和
- 2.22 513. 找树左下角的值
- 2.23 112.路径总和
- 2.24 113.路径总和 II
- 2.25 106. 从中序与后序遍历序列构造二叉树
- 2.26 105. 从前序与中序遍历序列构造二叉树
- 2.27 654. 最大二叉树
- 2.28 617. 合并二叉树
- 2.29 700. 二叉搜索树中的搜索
- 2.30 530. 二叉搜索树的最小绝对差
- 2.31 501. 二叉搜索树中的众数
- 2.32 236. 二叉树的最近公共祖先
- 2.33 235. 二叉搜索树的最近公共祖先
- 2.34 701. 二叉搜索树中的插入操作
- 2.35 450. 删除二叉搜索树中的节点
- 2.36 669. 修剪二叉搜索树
- 2.37 108. 将有序数组转换为二叉搜索树
- 2.38 538. 把二叉搜索树转换为累加树
- 2.39 2096. 从二叉树一个节点到另一个节点每一步的方向
- 2.40 剑指 Offer 26. 树的子结构
1.导论
- 1.满二叉树
除最后一层无任何子节点外,每一层上的所有结点都有两个子结点的二叉树。
- 2.完全二叉树
一棵深度为k的有n个结点的二叉树,对树中的结点按从上至下、从左到右的顺序进行编号,如果编号为i(1≤i≤n)的结点与满二叉树中编号为i的结点在二叉树中的位置相同,则这棵二叉树称为完全二叉树。
- 3.二叉搜索树(有序树)
它或者是一棵空树,或者是具有下列性质的二叉树: 若它的左子树不空,则左子树上所有结点的值均小于它的根结点的值; 若它的右子树不空,则右子树上所有结点的值均大于它的根结点的值; 它的左、右子树也分别为二叉排序树。
中序遍历出来是有序的
- 4.平衡二叉树
平衡二叉树要么是一棵空树. 要么保证左右子树的高度之差不大于 1. 子树也必须是一颗平衡二叉树.
-
5.二叉树的遍历
- 深度优先遍历(维护栈)
前序遍历(递归法,迭代法)
中序遍历(递归法,迭代法)
后序遍历(递归法,迭代法)- 广度优先遍历 (维护堆)
层次遍历(迭代法)
-
6.数据结构(能够手写出)
public class TreeNode { int val; TreeNode left; TreeNode right; TreeNode() {} TreeNode(int val) { this.val = val; } TreeNode(int val, TreeNode left, TreeNode right) { this.val = val; this.left = left; this.right = right; } }
2.编程题
2.1 144.二叉树的前序遍历
给你二叉树的根节点 root ,返回它节点值的 前序 遍历。
树中节点数目在范围 [0, 100] 内
-100 <= Node.val <= 100
//递归
class Solution {
public List<Integer> preorderTraversal(TreeNode root) {
List<Integer> res = new ArrayList<Integer>();
preorder(root, res);
return res;
}
public void preorder(TreeNode root, List<Integer> res) {
if (root == null) {
return;
}
res.add(root.val);
preorder(root.left, res);
preorder(root.right, res);
}
}
//迭代
class Solution {
public List<Integer> preorderTraversal(TreeNode root) {
List<Integer> res = new ArrayList<>();
Deque<TreeNode> stack = new LinkedList<>();
while(!stack.isEmpty() || root != null){
while(root != null){
res.add(root.val);
stack.push(root);
root = root.left;
}
root = stack.pop();
root = root.right;
}
return res;
}
}
2.2 94.二叉树的中序遍历
给定一个二叉树的根节点 root ,返回它的 中序 遍历。
树中节点数目在范围 [0, 100] 内
-100 <= Node.val <= 100
//递归
class Solution {
public List<Integer> inorderTraversal(TreeNode root) {
List<Integer> res = new ArrayList<Integer>();
inorder(root, res);
return res;
}
public void inorder(TreeNode root, List<Integer> res) {
if (root == null) {
return;
}
inorder(root.left, res);
res.add(root.val);
inorder(root.right, res);
}
}
//迭代
class Solution {
public List<Integer> inorderTraversal(TreeNode root) {
List<Integer> res = new ArrayList<Integer>();
Deque<TreeNode> stack = new LinkedList<TreeNode>();
while (root != null || !stack.isEmpty()) {
while (root != null) {
stack.push(root);
root = root.left;
}
root = stack.pop();
res.add(root.val);
root = root.right;
}
return res;
}
}
2.3 145.二叉树的后序遍历
给定一个二叉树,返回它的 后序 遍历。
//递归
class Solution {
public List<Integer> postorderTraversal(TreeNode root) {
List<Integer> res = new ArrayList<Integer>();
postorder(root, res);
return res;
}
public void postorder(TreeNode root, List<Integer> res) {
if (root == null) {
return;
}
postorder(root.left, res);
postorder(root.right, res);
res.add(root.val);
}
}
//迭代
class Solution {
public List<Integer> postorderTraversal(TreeNode root) {
List<Integer> res = new ArrayList<Integer>();
Deque<TreeNode> stack = new LinkedList<TreeNode>();
TreeNode prev = null;
while (root != null || !stack.isEmpty()) {
// 1.遍历到最左子节点
while (root != null) {
stack.push(root);
root = root.left;
}
root = stack.pop();
// 2.遍历最左子节点的右子树(右子树不存存在 && 还没有访问过)
if (root.right != null && root.right != prev) {
stack.push(root);
root = root.right;
} else {
// 注意:此时node的左右子树应均已完成访问
res.add(root.val);
// 避免重复访问右子树[记录当前节点便于下一步对比]
prev = root;
// 避免重复访问左子树[设空节点]
root = null;
}
}
return res;
}
}
2.4 102. 二叉树的层序遍历
给你一个二叉树,请你返回其按 层序遍历 得到的节点值。 (即逐层地,从左到右访问所有节点
//迭代
class Solution {
public List<List<Integer>> levelOrder(TreeNode root) {
List<List<Integer>> ret = new ArrayList<List<Integer>>();
if (root == null) {
return ret;
}
Queue<TreeNode> queue = new LinkedList<TreeNode>();
queue.offer(root);
while (!queue.isEmpty()) {
List<Integer> level = new ArrayList<Integer>();
int currentLevelSize = queue.size();
for (int i = 1; i <= currentLevelSize; ++i) {
TreeNode node = queue.poll();
level.add(node.val);
if (node.left != null) {
queue.offer(node.left);
}
if (node.right != null) {
queue.offer(node.right);
}
}
ret.add(level);
}
return ret;
}
}
//递归
class Solution {
List<List<Integer>> ans = new ArrayList<List<Integer>>();
public List<List<Integer>> levelOrder(TreeNode root) {
bfs(root,0);
return ans;
}
private void bfs(TreeNode root,int level){
if(root == null){
return;
}
if(level == ans.size()){
ans.add(new ArrayList<Integer>());
}
ans.get(level).add(root.val);
bfs(root.left,level+1);
bfs(root.right,level+1);
}
}
2.5 107. 二叉树的层序遍历 II
给定一个二叉树,返回其节点值自底向上的层序遍历。 (即按从叶子节点所在层到根节点所在的层,逐层从左向右遍历)
/**
* Definition for a binary tree node.
* public class TreeNode {
* int val;
* TreeNode left;
* TreeNode right;
* TreeNode() {}
* TreeNode(int val) { this.val = val; }
* TreeNode(int val, TreeNode left, TreeNode right) {
* this.val = val;
* this.left = left;
* this.right = right;
* }
* }
*/
class Solution {
public List<List<Integer>> levelOrderBottom(TreeNode root) {
List<List<Integer>> ret = new ArrayList<List<Integer>>();
if (root == null) {
return ret;
}
Queue<TreeNode> queue = new LinkedList<TreeNode>();
queue.offer(root);
while (!queue.isEmpty()) {
List<Integer> level = new ArrayList<Integer>();
int currentLevelSize = queue.size();
for (int i = 1; i <= currentLevelSize; ++i) {
TreeNode node = queue.poll();
level.add(node.val);
if (node.left != null) {
queue.offer(node.left);
}
if (node.right != null) {
queue.offer(node.right);
}
}
ret.add(0,level);
}
return ret;
}
}
//递归
class Solution {
List<List<Integer>> ans = new ArrayList<List<Integer>>();
public List<List<Integer>> levelOrderBottom(TreeNode root) {
bfs(root,0);
Collections.reverse(ans);
return ans;
}
private void bfs(TreeNode root,int level){
if(root == null){
return;
}
if(level == ans.size()){
ans.add(new ArrayList<Integer>());
}
ans.get(level).add(root.val);
bfs(root.left,level+1);
bfs(root.right,level+1);
}
}
2.6 199. 二叉树的右视图
给定一个二叉树的 根节点 root,想象自己站在它的右侧,按照从顶部到底部的顺序,返回从右侧所能看到的节点值。
二叉树的节点个数的范围是 [0,100]
-100 <= Node.val <= 100
/**
* Definition for a binary tree node.
* public class TreeNode {
* int val;
* TreeNode left;
* TreeNode right;
* TreeNode() {}
* TreeNode(int val) { this.val = val; }
* TreeNode(int val, TreeNode left, TreeNode right) {
* this.val = val;
* this.left = left;
* this.right = right;
* }
* }
*/
//迭代
class Solution {
public List<Integer> rightSideView(TreeNode root) {
List<Integer> ret = new ArrayList<>();
if (root == null) {
return ret;
}
Queue<TreeNode> queue = new LinkedList<TreeNode>();
queue.offer(root);
while (!queue.isEmpty()) {
int currentLevelSize = queue.size();
for (int i = 1; i <= currentLevelSize; ++i) {
TreeNode node = queue.poll();
if(i == currentLevelSize){
ret.add(node.val);
}
if (node.left != null) {
queue.offer(node.left);
}
if (node.right != null) {
queue.offer(node.right);
}
}
}
return ret;
}
}
//递归
class Solution {
List<Integer> list = new ArrayList<Integer>();
public List<Integer> rightSideView(TreeNode root) {
dfs(root,0);
return list;
}
//类比前序遍历,不过顺序是中右左
private void dfs(TreeNode root,int level){
if(root == null){
return;
}
if(list.size() == level){//表明此结点是当前层的最右节点
list.add(root.val);
}
dfs(root.right,level+1);
dfs(root.left,level+1);
}
}
2.7 637.二叉树的层平均值
给定一个非空二叉树, 返回一个由每层节点平均值组成的数组。
/**
* Definition for a binary tree node.
* public class TreeNode {
* int val;
* TreeNode left;
* TreeNode right;
* TreeNode() {}
* TreeNode(int val) { this.val = val; }
* TreeNode(int val, TreeNode left, TreeNode right) {
* this.val = val;
* this.left = left;
* this.right = right;
* }
* }
*/
class Solution {
public List<Double> averageOfLevels(TreeNode root) {
List<Double> ret = new ArrayList<>();
if (root == null) {
return ret;
}
Queue<TreeNode> queue = new LinkedList<TreeNode>();
queue.offer(root);
while (!queue.isEmpty()) {
int currentLevelSize = queue.size();
double sum= 0;
for (int i = 1; i <= currentLevelSize; ++i) {
TreeNode node = queue.poll();
sum += node.val;
if (node.left != null) {
queue.offer(node.left);
}
if (node.right != null) {
queue.offer(node.right);
}
}
ret.add((sum/currentLevelSize));
}
return ret;
}
}
2.8 429.N叉树的层序遍历
给定一个 N 叉树,返回其节点值的层序遍历。(即从左到右,逐层遍历)。
树的序列化输入是用层序遍历,每组子节点都由 null 值分隔(参见示例)。
树的高度不会超过 1000
树的节点总数在 [0, 10^4] 之间
/*
// Definition for a Node.
class Node {
public int val;
public List<Node> children;
public Node() {}
public Node(int _val) {
val = _val;
}
public Node(int _val, List<Node> _children) {
val = _val;
children = _children;
}
};
*/
class Solution {
public List<List<Integer>> levelOrder(Node root) {
List<List<Integer>> ret = new ArrayList<List<Integer>>();
if (root == null) {
return ret;
}
Queue<Node> queue = new LinkedList<Node>();
queue.offer(root);
while (!queue.isEmpty()) {
List<Integer> level = new ArrayList<Integer>();
int currentLevelSize = queue.size();
for (int i = 1; i <= currentLevelSize; ++i) {
Node node = queue.poll();
level.add(node.val);
for(int j=0;j<node.children.size();++j){
queue.offer(node.children.get(j));
}
}
ret.add(level);
}
return ret;
}
}
//递归
class Solution {
private List<List<Integer>> result = new ArrayList<>();
public List<List<Integer>> levelOrder(Node root) {
if (root != null) traverseNode(root, 0);
return result;
}
private void traverseNode(Node node, int level) {
if (result.size() <= level) {
result.add(new ArrayList<>());
}
result.get(level).add(node.val);
for (Node child : node.children) {
traverseNode(child, level + 1);
}
}
}
2.9 515.在每个树行中找最大值
给定一棵二叉树的根节点 root ,请找出该二叉树中每一层的最大值。
二叉树的节点个数的范围是 [0,104]
-231 <= Node.val <= 231 - 1
/**
* Definition for a binary tree node.
* public class TreeNode {
* int val;
* TreeNode left;
* TreeNode right;
* TreeNode() {}
* TreeNode(int val) { this.val = val; }
* TreeNode(int val, TreeNode left, TreeNode right) {
* this.val = val;
* this.left = left;
* this.right = right;
* }
* }
*/
//迭代
class Solution {
public List<Integer> largestValues(TreeNode root) {
List<Integer> ret = new ArrayList<>();
if(root == null){
return ret;
}
Queue<TreeNode> queue = new LinkedList<>();
queue.offer(root);
while(!queue.isEmpty()){
int currentLevelSize = queue.size();
int currentLevelMax = Integer.MIN_VALUE;
for(int i=1;i<=currentLevelSize;++i){
TreeNode node = queue.poll();
currentLevelMax = Math.max(node.val,currentLevelMax);
if(node.left != null){
queue.offer(node.left);
}
if(node.right != null){
queue.offer(node.right);
}
}
ret.add(currentLevelMax);
}
return ret;
}
}
//递归
class Solution {
List<Integer> res = new ArrayList<>();
public List<Integer> largestValues(TreeNode root) {
levelOrder(root, 0);
return res;
}
private void levelOrder(TreeNode root, int level) {
if (root == null) {
return;
}
if (level >= res.size()) {
res.add(level, root.val);
} else {
Integer val = res.get(level);
if (root.val > val) {
res.set(level, root.val);
}
}
levelOrder(root.left, level + 1);
levelOrder(root.right, level + 1);
}
}
2.10 116. 填充每个节点的下一个右侧节点指针
给定一个 完美二叉树 ,其所有叶子节点都在同一层,每个父节点都有两个子节点。二叉树定义如下:
struct Node {
int val;
Node *left;
Node *right;
Node *next;
}
填充它的每个 next 指针,让这个指针指向其下一个右侧节点。如果找不到下一个右侧节点,则将 next 指针设置为 NULL。
初始状态下,所有 next 指针都被设置为 NULL。
进阶:
你只能使用常量级额外空间。
使用递归解题也符合要求,本题中递归程序占用的栈空间不算做额外的空间复杂度。
树中节点的数量少于 4096
-1000 <= node.val <= 1000
/*
// 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) {
if (root == null) {
return root;
}
// 初始化队列同时将第一层节点加入队列中,即根节点
Queue<Node> queue = new LinkedList<Node>();
queue.offer(root);
// 外层的 while 循环迭代的是层数
while (!queue.isEmpty()) {
// 记录当前队列大小
int currentLevelSize = queue.size();
// 遍历这一层的所有节点
for (int i = 1; i <= currentLevelSize; i++) {
// 从队首取出元素
Node node = queue.poll();
// 连接
if (i < currentLevelSize) {
node.next = queue.peek();
}
// 拓展下一层节点
if (node.left != null) {
queue.add(node.left);
}
if (node.right != null) {
queue.add(node.right);
}
}
}
// 返回根节点
return root;
}
}
//迭代
class Solution {
public Node connect(Node root) {
if (root == null) {
return root;
}
// 从根节点开始
Node leftmost = root;
while (leftmost.left != null) {
// 遍历这一层节点组织成的链表,为下一层的节点更新 next 指针
Node head = leftmost;
while (head != null) {
// CONNECTION 1
head.left.next = head.right;
// CONNECTION 2
if (head.next != null) {
head.right.next = head.next.left;
}
// 指针向后移动
head = head.next;
}
// 去下一层的最左的节点
leftmost = leftmost.left;
}
return root;
}
}
//递归
class Solution {
public Node connect(Node root) {
if(root == null || root.left == null){
return root;
}
root.left.next = root.right;
if(root.next != null){
root.right.next = root.next.left;
}
connect(root.left);
connect(root.right);
return root;
}
}
2.11 117. 填充每个节点的下一个右侧节点指针 II
给定一个二叉树
struct Node {
int val;
Node *left;
Node *right;
Node *next;
}
填充它的每个 next 指针,让这个指针指向其下一个右侧节点。如果找不到下一个右侧节点,则将 next 指针设置为 NULL。
初始状态下,所有 next 指针都被设置为 NULL。
进阶:
你只能使用常量级额外空间。
使用递归解题也符合要求,本题中递归程序占用的栈空间不算做额外的空间复杂度。
树中的节点数小于 6000
-100 <= node.val <= 100
/*
// 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) {
if (root == null) {
return root;
}
// 初始化队列同时将第一层节点加入队列中,即根节点
Queue<Node> queue = new LinkedList<Node>();
queue.offer(root);
// 外层的 while 循环迭代的是层数
while (!queue.isEmpty()) {
// 记录当前队列大小
int currentLevelSize = queue.size();
// 遍历这一层的所有节点
for (int i = 1; i <= currentLevelSize; i++) {
// 从队首取出元素
Node node = queue.poll();
// 连接
if (i < currentLevelSize) {
node.next = queue.peek();
}
// 拓展下一层节点
if (node.left != null) {
queue.add(node.left);
}
if (node.right != null) {
queue.add(node.right);
}
}
}
// 返回根节点
return root;
}
}
//递归
class Solution {
public Node connect(Node root) {
connect1(root);
return root;
}
public void connect1(Node root) {
if(root == null || (root.left == null && root.right == null)){
return;
}
if(root.left != null && root.right != null){
root.left.next = root.right;
}
Node cur = root.right != null ? root.right : root.left;
Node temp = root.next;
while(temp != null){
if(temp.left != null){
cur.next = temp.left;
break;
}else if(temp.right != null){
cur.next = temp.right;
break;
}
temp = temp.next;
}
connect1(root.right);
connect1(root.left);
}
}
2.12 104. 二叉树的最大深度
给定一个二叉树,找出其最大深度。
二叉树的深度为根节点到最远叶子节点的最长路径上的节点数。
说明: 叶子节点是指没有子节点的节点。
/**
* Definition for a binary tree node.
* public class TreeNode {
* int val;
* TreeNode left;
* TreeNode right;
* TreeNode() {}
* TreeNode(int val) { this.val = val; }
* TreeNode(int val, TreeNode left, TreeNode right) {
* this.val = val;
* this.left = left;
* this.right = right;
* }
* }
*/
//迭代
class Solution {
public int maxDepth(TreeNode root) {
if(root == null){
return 0;
}
Queue<TreeNode> queue = new LinkedList<TreeNode>();
int res = 0;
queue.offer(root);
while(!queue.isEmpty()){
int size = queue.size();
res++;
for(int i=1;i<=size;++i){
root = queue.poll();
if(root.left != null){
queue.offer(root.left);
}
if(root.right != null){
queue.offer(root.right);
}
}
}
return res;
}
}
//递归
class Solution {
public int maxDepth(TreeNode root) {
return root == null ? 0 : Math.max(maxDepth(root.left),maxDepth(root.right))+1;
}
}
2.13 111. 二叉树的最小深度
给定一个二叉树,找出其最小深度。
最小深度是从根节点到最近叶子节点的最短路径上的节点数量。
说明:叶子节点是指没有子节点的节点。
树中节点数的范围在 [0, 105] 内
-1000 <= Node.val <= 1000
/**
* Definition for a binary tree node.
* public class TreeNode {
* int val;
* TreeNode left;
* TreeNode right;
* TreeNode() {}
* TreeNode(int val) { this.val = val; }
* TreeNode(int val, TreeNode left, TreeNode right) {
* this.val = val;
* this.left = left;
* this.right = right;
* }
* }
*/
//迭代
class Solution {
public int minDepth(TreeNode root) {
if(root == null){
return 0;
}
Queue<TreeNode> queue = new LinkedList<TreeNode>();
int res = 0;
queue.offer(root);
while(!queue.isEmpty()){
int size = queue.size();
res++;
for(int i=1;i<=size;++i){
TreeNode node = queue.poll();
if(node.left != null){
queue.offer(node.left);
}
if(node.right != null){
queue.offer(node.right);
}
if(node.left==null && node.right == null){
return res;
}
}
}
return res;
}
}
//递归
class Solution {
public int minDepth(TreeNode root) {
if (root == null) {
return 0;
}
if (root.left == null && root.right == null) {
return 1;
}
int min_depth = Integer.MAX_VALUE;
if (root.left != null) {
min_depth = Math.min(minDepth(root.left), min_depth);
}
if (root.right != null) {
min_depth = Math.min(minDepth(root.right), min_depth);
}
return min_depth + 1;
}
}
2.14 226. 翻转二叉树
翻转一棵二叉树。
/**
* Definition for a binary tree node.
* public class TreeNode {
* int val;
* TreeNode left;
* TreeNode right;
* TreeNode() {}
* TreeNode(int val) { this.val = val; }
* TreeNode(int val, TreeNode left, TreeNode right) {
* this.val = val;
* this.left = left;
* this.right = right;
* }
* }
*/
//递归
class Solution {
public TreeNode invertTree(TreeNode root) {
if (root == null) {
return null;
}
TreeNode left = invertTree(root.left);
TreeNode right = invertTree(root.right);
root.left = right;
root.right = left;
return root;
}
}
2.15 101. 对称二叉树
给定一个二叉树,检查它是否是镜像对称的。
//递归
class Solution {
public boolean isSymmetric(TreeNode root) {
return check(root, root);
}
public boolean check(TreeNode p, TreeNode q) {
if (p == null && q == null) {
return true;
}
if (p == null || q == null) {
return false;
}
return p.val == q.val && check(p.left, q.right) && check(p.right, q.left);
}
}
//迭代
class Solution {
public boolean isSymmetric(TreeNode root) {
return check(root, root);
}
public boolean check(TreeNode u, TreeNode v) {
Queue<TreeNode> q = new LinkedList<TreeNode>();
q.offer(u);
q.offer(v);
while (!q.isEmpty()) {
u = q.poll();
v = q.poll();
if (u == null && v == null) {
continue;
}
if ((u == null || v == null) || (u.val != v.val)) {
return false;
}
q.offer(u.left);
q.offer(v.right);
q.offer(u.right);
q.offer(v.left);
}
return true;
}
}
2.16 100. 相同的树
给你两棵二叉树的根节点 p 和 q ,编写一个函数来检验这两棵树是否相同。
如果两个树在结构上相同,并且节点具有相同的值,则认为它们是相同的。
两棵树上的节点数目都在范围 [0, 100] 内
-104 <= Node.val <= 104
/**
* Definition for a binary tree node.
* public class TreeNode {
* int val;
* TreeNode left;
* TreeNode right;
* TreeNode() {}
* TreeNode(int val) { this.val = val; }
* TreeNode(int val, TreeNode left, TreeNode right) {
* this.val = val;
* this.left = left;
* this.right = right;
* }
* }
*/
//递归
class Solution {
public boolean isSameTree(TreeNode p, TreeNode q) {
if (p == null && q == null) {
return true;
} else if (p == null || q == null) {
return false;
} else if (p.val != q.val) {
return false;
} else {
return isSameTree(p.left, q.left) && isSameTree(p.right, q.right);
}
}
}
//迭代
/**
* Definition for a binary tree node.
* public class TreeNode {
* int val;
* TreeNode left;
* TreeNode right;
* TreeNode() {}
* TreeNode(int val) { this.val = val; }
* TreeNode(int val, TreeNode left, TreeNode right) {
* this.val = val;
* this.left = left;
* this.right = right;
* }
* }
*/
class Solution {
public boolean isSameTree(TreeNode p, TreeNode q) {
Queue<TreeNode> tmpQueue = new LinkedList<TreeNode>();
tmpQueue.offer(p);
tmpQueue.offer(q);
while(!tmpQueue.isEmpty()){
p = tmpQueue.poll();
q = tmpQueue.poll();
if(p == null && q == null){
continue;
}
if((p == null || q == null) || p.val != q.val){
return false;
}
tmpQueue.offer(p.left);
tmpQueue.offer(q.left);
tmpQueue.offer(p.right);
tmpQueue.offer(q.right);
}
return true;
}
}
2.17 572. 另一棵树的子树
给你两棵二叉树 root 和 subRoot 。检验 root 中是否包含和 subRoot 具有相同结构和节点值的子树。如果存在,返回 true ;否则,返回 false 。
二叉树 tree 的一棵子树包括 tree 的某个节点和这个节点的所有后代节点。tree 也可以看做它自身的一棵子树。
root 树上的节点数量范围是 [1, 2000]
subRoot 树上的节点数量范围是 [1, 1000]
-104 <= root.val <= 104
-104 <= subRoot.val <= 104
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/subtree-of-another-tree
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
//递归
class Solution {
public boolean isSubtree(TreeNode s, TreeNode t) {
return dfs(s, t);
}
public boolean dfs(TreeNode s, TreeNode t) {
if (s == null) {
return false;
}
return check(s, t) || dfs(s.left, t) || dfs(s.right, t);
}
public boolean check(TreeNode s, TreeNode t) {
if (s == null && t == null) {
return true;
}
if (s == null || t == null || s.val != t.val) {
return false;
}
return check(s.left, t.left) && check(s.right, t.right);
}
}
2.18 222. 完全二叉树的节点个数
给你一棵 完全二叉树 的根节点 root ,求出该树的节点个数。
完全二叉树 的定义如下:在完全二叉树中,除了最底层节点可能没填满外,其余每层节点数都达到最大值,并且最下面一层的节点都集中在该层最左边的若干位置。若最底层为第 h 层,则该层包含 1~ 2h 个节点。
树中节点的数目范围是[0, 5 * 104]
0 <= Node.val <= 5 * 104
题目数据保证输入的树是 完全二叉树
/**
* Definition for a binary tree node.
* public class TreeNode {
* int val;
* TreeNode left;
* TreeNode right;
* TreeNode() {}
* TreeNode(int val) { this.val = val; }
* TreeNode(int val, TreeNode left, TreeNode right) {
* this.val = val;
* this.left = left;
* this.right = right;
* }
* }
*/
//递归
class Solution {
public int countNodes(TreeNode root) {
if(root == null) {
return 0;
}
return countNodes(root.left) + countNodes(root.right) + 1;
}
}
//递归
class Solution {
/**
完全二叉树的高度可以直接通过不断地访问左子树就可以获取
判断左右子树的高度:
如果相等说明左子树是满二叉树, 然后进一步判断右子树的节点数(最后一层最后出现的节点必然在右子树中)
如果不等说明右子树是深度小于左子树的满二叉树, 然后进一步判断左子树的节点数(最后一层最后出现的节点必然在左子树中)
**/
public int countNodes(TreeNode root) {
if(root==null){
return 0;
}
int leftDepth = getDepth(root.left);
int rightDepth = getDepth(root.right);
if(leftDepth == rightDepth){
return (1<<leftDepth) + countNodes(root.right);// 1(根节点) + (1 << ld)-1(左完全左子树节点数) + 右子树节点数量
}else{
return (1<<rightDepth) + countNodes(root.left);//1(根节点) + (1 << rd)-1(右完全右子树节点数) + 左子树节点数量
}
}
//计算树的深度
private int getDepth(TreeNode root){
int depth = 0;
while(root != null){
depth++;
root = root.left;
}
return depth;
}
}
2.19 110. 平衡二叉树
给定一个二叉树,判断它是否是高度平衡的二叉树。
本题中,一棵高度平衡二叉树定义为:
一个二叉树每个节点 的左右两个子树的高度差的绝对值不超过 1 。
树中的节点数在范围 [0, 5000] 内
-104 <= Node.val <= 104
/**
* Definition for a binary tree node.
* public class TreeNode {
* int val;
* TreeNode left;
* TreeNode right;
* TreeNode() {}
* TreeNode(int val) { this.val = val; }
* TreeNode(int val, TreeNode left, TreeNode right) {
* this.val = val;
* this.left = left;
* this.right = right;
* }
* }
*/
/**
* Definition for a binary tree node.
* public class TreeNode {
* int val;
* TreeNode left;
* TreeNode right;
* TreeNode() {}
* TreeNode(int val) { this.val = val; }
* TreeNode(int val, TreeNode left, TreeNode right) {
* this.val = val;
* this.left = left;
* this.right = right;
* }
* }
*/
//递归
class Solution {
public boolean isBalanced(TreeNode root) {
if(root == null){
return true;
}
return Math.abs(height(root.left)-height(root.right))<=1 && isBalanced(root.left) && isBalanced(root.right);
}
//求每个结点的高度
private int height(TreeNode root){
if(root == null){
return 0;
}else{
return Math.max(height(root.left),height(root.right))+1;
}
}
}
//递归
class Solution {
public boolean isBalanced(TreeNode root) {
return height(root) != -1;
}
//求每个结点的高度
private int height(TreeNode root){
if(root == null){
return 0;
}
//类似于后序遍历
int leftHeight = height(root.left);
int rightHeight = height(root.right);
if(leftHeight == -1 || rightHeight == -1 || Math.abs(leftHeight-rightHeight)>1){
return -1;
}else{
return Math.max(leftHeight,rightHeight)+1;
}
}
}
2.20 257. 二叉树的所有路径
给你一个二叉树的根节点 root ,按 任意顺序 ,返回所有从根节点到叶子节点的路径。
叶子节点 是指没有子节点的节点。
/**
* Definition for a binary tree node.
* public class TreeNode {
* int val;
* TreeNode left;
* TreeNode right;
* TreeNode() {}
* TreeNode(int val) { this.val = val; }
* TreeNode(int val, TreeNode left, TreeNode right) {
* this.val = val;
* this.left = left;
* this.right = right;
* }
* }
*/
//递归
class Solution {
List<String> paths = new ArrayList<String>();
public List<String> binaryTreePaths(TreeNode root) {
constructPaths(root, "");
return paths;
}
public void constructPaths(TreeNode root, String path) {
if(root == null){
return;
}
StringBuffer pathSB = new StringBuffer(path);
pathSB.append(Integer.toString(root.val));
if (root.left == null && root.right == null) { // 当前节点是叶子节点
paths.add(pathSB.toString()); // 把路径加入到答案中
} else {
pathSB.append("->"); // 当前节点不是叶子节点,继续递归遍历
constructPaths(root.left, pathSB.toString());
constructPaths(root.right, pathSB.toString());
}
}
}
//迭代
class Solution {
public List<String> binaryTreePaths(TreeNode root) {
List<String> paths = new ArrayList<String>();
if (root == null) {
return paths;
}
Queue<TreeNode> nodeQueue = new LinkedList<TreeNode>();
Queue<String> pathQueue = new LinkedList<String>();
nodeQueue.offer(root);
pathQueue.offer(Integer.toString(root.val));
while (!nodeQueue.isEmpty()) {
TreeNode node = nodeQueue.poll();
String path = pathQueue.poll();
if (node.left == null && node.right == null) {
paths.add(path);
} else {
if (node.left != null) {
nodeQueue.offer(node.left);
pathQueue.offer(new StringBuffer(path).append("->").append(node.left.val).toString());
}
if (node.right != null) {
nodeQueue.offer(node.right);
pathQueue.offer(new StringBuffer(path).append("->").append(node.right.val).toString());
}
}
}
return paths;
}
}
2.21 404. 左叶子之和
计算给定二叉树的所有左叶子之和。
/**
* Definition for a binary tree node.
* public class TreeNode {
* int val;
* TreeNode left;
* TreeNode right;
* TreeNode() {}
* TreeNode(int val) { this.val = val; }
* TreeNode(int val, TreeNode left, TreeNode right) {
* this.val = val;
* this.left = left;
* this.right = right;
* }
* }
*/
//递归
class Solution {
//后续遍历
public int sumOfLeftLeaves(TreeNode root) {
if(root == null){
return 0;
}
int leftValue = sumOfLeftLeaves(root.left);
int rightValue = sumOfLeftLeaves(root.right);
int midValue = 0;
if(root.left != null && root.left.left == null && root.left.right == null){
midValue = root.left.val;
}
return midValue + leftValue + rightValue;
}
}
//迭代
class Solution {
public int sumOfLeftLeaves(TreeNode root) {
if (root == null) {
return 0;
}
Queue<TreeNode> queue = new LinkedList<TreeNode>();
queue.offer(root);
int ans = 0;
while (!queue.isEmpty()) {
TreeNode node = queue.poll();
if (node.left != null) {
if (isLeafNode(node.left)) {
ans += node.left.val;
} else {
queue.offer(node.left);
}
}
if (node.right != null) {
if (!isLeafNode(node.right)) {
queue.offer(node.right);
}
}
}
return ans;
}
public boolean isLeafNode(TreeNode node) {
return node.left == null && node.right == null;
}
}
2.22 513. 找树左下角的值
给定一个二叉树的 根节点 root,请找出该二叉树的 最底层 最左边 节点的值。
假设二叉树中至少有一个节点。
二叉树的节点个数的范围是 [1,104]
-231 <= Node.val <= 231 - 1
/**
* Definition for a binary tree node.
* public class TreeNode {
* int val;
* TreeNode left;
* TreeNode right;
* TreeNode() {}
* TreeNode(int val) { this.val = val; }
* TreeNode(int val, TreeNode left, TreeNode right) {
* this.val = val;
* this.left = left;
* this.right = right;
* }
* }
*/
// 递归
class Solution {
private int Deep = -1;
private int value = 0;
public int findBottomLeftValue(TreeNode root) {
findLeftValue(root,0);
return value;
}
private void findLeftValue (TreeNode root,int deep) {
if (root == null) return;
if (root.left == null && root.right == null) {
if (deep > Deep) {
value = root.val;
Deep = deep;
}
}
if (root.left != null) findLeftValue(root.left,deep + 1);
if (root.right != null) findLeftValue(root.right,deep + 1);
}
}
//迭代
class Solution {
public int findBottomLeftValue(TreeNode root) {
Queue<TreeNode> queue = new LinkedList<>();
queue.offer(root);
int res = 0;
while (!queue.isEmpty()) {
int size = queue.size();
for (int i = 1; i <= size; i++) {
TreeNode poll = queue.poll();
if (i == 1) {
res = poll.val;
}
if (poll.left != null) {
queue.offer(poll.left);
}
if (poll.right != null) {
queue.offer(poll.right);
}
}
}
return res;
}
}
2.23 112.路径总和
给你二叉树的根节点 root 和一个表示目标和的整数 targetSum ,判断该树中是否存在 根节点到叶子节点 的路径,这条路径上所有节点值相加等于目标和 targetSum 。
树中节点的数目在范围 [0, 5000] 内
-1000 <= Node.val <= 1000
-1000 <= targetSum <= 1000
/**
* Definition for a binary tree node.
* public class TreeNode {
* int val;
* TreeNode left;
* TreeNode right;
* TreeNode() {}
* TreeNode(int val) { this.val = val; }
* TreeNode(int val, TreeNode left, TreeNode right) {
* this.val = val;
* this.left = left;
* this.right = right;
* }
* }
*/
//递归
class Solution {
public boolean hasPathSum(TreeNode root, int targetSum) {
if(root == null){
return false;
}
if(root.left == null && root.right == null){
return root.val == targetSum;
}
return hasPathSum(root.left,targetSum - root.val) || hasPathSum(root.right,targetSum-root.val);
}
}
//迭代
class Solution {
public boolean hasPathSum(TreeNode root, int targetSum) {
if(root == null){
return false;
}
Queue<TreeNode> queueNode = new LinkedList<>();
Queue<Integer> queueVal = new LinkedList<>();
queueNode.offer(root);
queueVal.offer(root.val);
while(!queueNode.isEmpty()){
TreeNode node = queueNode.poll();
int curLevelSum = queueVal.poll();
if(node.left == null && node.right == null){
if(curLevelSum == targetSum){
return true;
}
continue;
}
if(node.left != null){
queueNode.offer(node.left);
queueVal.offer(curLevelSum+node.left.val);
}
if(node.right != null){
queueNode.offer(node.right);
queueVal.offer(curLevelSum + node.right.val);
}
}
return false;
}
}
2.24 113.路径总和 II
- 路径总和 II
给你二叉树的根节点 root 和一个整数目标和 targetSum ,找出所有 从根节点到叶子节点 路径总和等于给定目标和的路径。
叶子节点 是指没有子节点的节点。
树中节点总数在范围 [0, 5000] 内
-1000 <= Node.val <= 1000
-1000 <= targetSum <= 1000
/**
* Definition for a binary tree node.
* public class TreeNode {
* int val;
* TreeNode left;
* TreeNode right;
* TreeNode() {}
* TreeNode(int val) { this.val = val; }
* TreeNode(int val, TreeNode left, TreeNode right) {
* this.val = val;
* this.left = left;
* this.right = right;
* }
* }
*/
class Solution {
List<List<Integer>> ret = new ArrayList<List<Integer>>();
List<Integer> path = new ArrayList<>();
public List<List<Integer>> pathSum(TreeNode root, int targetSum) {
dfs(root,targetSum);
return ret;
}
private void dfs(TreeNode root,int targetSum){
if(root == null){
return;
}
path.add(root.val);
if(root.left == null && root.right == null && root.val == targetSum){
ret.add(new ArrayList(path));
}
dfs(root.left,targetSum-root.val);
dfs(root.right,targetSum-root.val);
path.remove(path.size()-1);
}
}
2.25 106. 从中序与后序遍历序列构造二叉树
根据一棵树的中序遍历与后序遍历构造二叉树。
注意:
你可以假设树中没有重复的元素。
/**
* Definition for a binary tree node.
* public class TreeNode {
* int val;
* TreeNode left;
* TreeNode right;
* TreeNode() {}
* TreeNode(int val) { this.val = val; }
* TreeNode(int val, TreeNode left, TreeNode right) {
* this.val = val;
* this.left = left;
* this.right = right;
* }
* }
*/
class Solution {
/*
前序/后序+中序序列可以唯一确定一棵二叉树,所以自然而然可以用来建树。
看一下中序和后序有什么特点,中序[9,3,15,20,7] ,后序[9,15,7,20,3];
有如下特征:
1.后序中右起第一位3肯定是根结点,我们可以据此找到中序中根结点的位置;
2.中序中根结点左边就是左子树结点,右边就是右子树结点,即[左子树结点,根结点,右子树结点],我们就可以得出左子树结点个数
3.后序中结点分布应该是:[左子树结点,右子树结点,根结点];
4.根据前一步确定的左子树个数,可以确定后序中左子树结点和右子树结点的范围;
5.如果我们要前序遍历生成二叉树的话,下一层递归应该是:
左子树:root.left = preOrder(中序左子树范围,后序左子树范围,中序序列,后序序列);;
右子树:root.right = preOrder(中序右子树范围,后序右子树范围,中序序列,后序序列);。
6.每一层递归都要返回当前根结点root
*/
public TreeNode buildTree(int[] inorder, int[] postorder) {
return preOrder(0,inorder.length-1,0,postorder.length-1,inorder,postorder);
}
private TreeNode preOrder(int l1,int r1,int l2,int r2,int[] inorder,int[] postorder){
if(l1>r1) return null;
int index = l1;
while(inorder[index] != postorder[r2]){
//找到中序遍历中的根节点,则根节点的左边是左子节点,右边是右子节点
++index;
}
int leftCount = index-l1;//左子节点的个数
TreeNode root = new TreeNode(postorder[r2]);
root.left = preOrder(l1,index-1,l2,l2+leftCount-1,inorder,postorder);
root.right = preOrder(index+1,r1,l2+leftCount,r2-1,inorder,postorder);
return root;
}
}
//优化,使用hashmap加快索引
class Solution {
Map<Integer,Integer> indexMap = new HashMap<>();
public TreeNode buildTree(int[] inorder, int[] postorder) {
int n = postorder.length;
// 构造哈希映射,帮助我们快速定位根节点
indexMap = new HashMap<Integer, Integer>();
for (int i = 0; i < n; i++) {
indexMap.put(inorder[i], i);
}
return preOrder(0,n-1,0,n-1,inorder,postorder);
}
private TreeNode preOrder(int l1,int r1,int l2,int r2,int[] inorder,int[] postorder){
if(l1>r1) return null;
int index = indexMap.get(postorder[r2]);
int leftCount = index-l1;//左子节点的个数
TreeNode root = new TreeNode(postorder[r2]);
root.left = preOrder(l1,index-1,l2,l2+leftCount-1,inorder,postorder);
root.right = preOrder(index+1,r1,l2+leftCount,r2-1,inorder,postorder);
return root;
}
}
2.26 105. 从前序与中序遍历序列构造二叉树
给定一棵树的前序遍历 preorder 与中序遍历 inorder。请构造二叉树并返回其根节点。
1 <= preorder.length <= 3000
inorder.length == preorder.length
-3000 <= preorder[i], inorder[i] <= 3000
preorder 和 inorder 均无重复元素
inorder 均出现在 preorder
preorder 保证为二叉树的前序遍历序列
inorder 保证为二叉树的中序遍历序列
/**
* Definition for a binary tree node.
* public class TreeNode {
* int val;
* TreeNode left;
* TreeNode right;
* TreeNode() {}
* TreeNode(int val) { this.val = val; }
* TreeNode(int val, TreeNode left, TreeNode right) {
* this.val = val;
* this.left = left;
* this.right = right;
* }
* }
*/
class Solution {
public TreeNode buildTree(int[] preorder, int[] inorder) {
return preorder(0,inorder.length-1,0,preorder.length-1,inorder,preorder);
}
public TreeNode preorder(int l1,int r1,int l2,int r2,int[] inorder,int[] preorder){
if(l1>r1){
return null;
}
int index = l1;
while(inorder[index] != preorder[l2]){
++index;
}
int leftCount = index-l1;
TreeNode root = new TreeNode(preorder[l2]);
root.left = preorder(l1,index-1,l2+1,l2+leftCount,inorder,preorder);
root.right = preorder(index+1,r1,l2+leftCount+1,r2,inorder,preorder);
return root;
}
}
//优化,使用hashmap加快索引
class Solution {
Map<Integer,Integer> indexMap = new HashMap<>();
public TreeNode buildTree(int[] preorder, int[] inorder) {
int n = preorder.length;
// 构造哈希映射,帮助我们快速定位根节点
indexMap = new HashMap<Integer, Integer>();
for (int i = 0; i < n; i++) {
indexMap.put(inorder[i], i);
}
return preorder(0,n-1,0,n-1,inorder,preorder);
}
public TreeNode preorder(int l1,int r1,int l2,int r2,int[] inorder,int[] preorder){
if(l1>r1){
return null;
}
int index = indexMap.get(preorder[l2]);
int leftCount = index-l1;
TreeNode root = new TreeNode(preorder[l2]);
root.left = preorder(l1,index-1,l2+1,l2+leftCount,inorder,preorder);
root.right = preorder(index+1,r1,l2+leftCount+1,r2,inorder,preorder);
return root;
}
}
2.27 654. 最大二叉树
给定一个不含重复元素的整数数组 nums 。一个以此数组直接递归构建的 最大二叉树 定义如下:
二叉树的根是数组 nums 中的最大元素。
左子树是通过数组中 最大值左边部分 递归构造出的最大二叉树。
右子树是通过数组中 最大值右边部分 递归构造出的最大二叉树。
返回有给定数组 nums 构建的 最大二叉树 。
1 <= nums.length <= 1000
0 <= nums[i] <= 1000
nums 中的所有整数 互不相同
/**
* Definition for a binary tree node.
* public class TreeNode {
* int val;
* TreeNode left;
* TreeNode right;
* TreeNode() {}
* TreeNode(int val) { this.val = val; }
* TreeNode(int val, TreeNode left, TreeNode right) {
* this.val = val;
* this.left = left;
* this.right = right;
* }
* }
*/
class Solution {
public TreeNode constructMaximumBinaryTree(int[] nums) {
return preOrder(0,nums.length-1,nums);
}
public TreeNode preOrder(int l,int r,int[] nums){
if(l>r){
return null;
}
int maxIndex = getMaxIndex(l,r,nums);
TreeNode root = new TreeNode(nums[maxIndex]);
root.left = preOrder(l,maxIndex-1,nums);
root.right = preOrder(maxIndex+1,r,nums);
return root;
}
public int getMaxIndex(int l,int r,int[] nums){
int maxIndex = l;
for(int i=l;i<=r;++i){
if(nums[i]>nums[maxIndex]){
maxIndex = i;
}
}
return maxIndex;
}
}
2.28 617. 合并二叉树
给定两个二叉树,想象当你将它们中的一个覆盖到另一个上时,两个二叉树的一些节点便会重叠。
你需要将他们合并为一个新的二叉树。合并的规则是如果两个节点重叠,那么将他们的值相加作为节点合并后的新值,否则不为 NULL 的节点将直接作为新二叉树的节点。
class Solution {
public TreeNode mergeTrees(TreeNode t1, TreeNode t2) {
if (t1 == null) {
return t2;
}
if (t2 == null) {
return t1;
}
TreeNode root = new TreeNode(t1.val + t2.val);
root.left = mergeTrees(t1.left, t2.left);
root.right = mergeTrees(t1.right, t2.right);
return root;
}
}
2.29 700. 二叉搜索树中的搜索
给定二叉搜索树(BST)的根节点和一个值。 你需要在BST中找到节点值等于给定值的节点。 返回以该节点为根的子树。 如果节点不存在,则返回 NULL。
/**
* Definition for a binary tree node.
* public class TreeNode {
* int val;
* TreeNode left;
* TreeNode right;
* TreeNode() {}
* TreeNode(int val) { this.val = val; }
* TreeNode(int val, TreeNode left, TreeNode right) {
* this.val = val;
* this.left = left;
* this.right = right;
* }
* }
*/
//递归
class Solution {
public TreeNode searchBST(TreeNode root, int val) {
if(root == null || root.val == val){
return root;
}
if(root.val < val) return searchBST(root.right,val);
if(root.val > val) return searchBST(root.left,val);
return null;
}
}
//迭代
class Solution {
public TreeNode searchBST(TreeNode root, int val) {
while (root != null && val != root.val){
root = val < root.val ? root.left : root.right;
}
return root;
}
}
2.30 530. 二叉搜索树的最小绝对差
给你一个二叉搜索树的根节点 root ,返回 树中任意两不同节点值之间的最小差值 。
差值是一个正数,其数值等于两值之差的绝对值。
树中节点的数目范围是 [2, 104]
0 <= Node.val <= 105
/**
* Definition for a binary tree node.
* public class TreeNode {
* int val;
* TreeNode left;
* TreeNode right;
* TreeNode() {}
* TreeNode(int val) { this.val = val; }
* TreeNode(int val, TreeNode left, TreeNode right) {
* this.val = val;
* this.left = left;
* this.right = right;
* }
* }
*/
class Solution {
List<Integer> list = new ArrayList<>();
public int getMinimumDifference(TreeNode root) {
int ans = Integer.MAX_VALUE;
inorder(root);
for(int i=1;i<list.size();++i){
ans = Math.min(ans,(list.get(i)-list.get(i-1)));
}
return ans;
}
public void inorder(TreeNode root){
if(root == null){
return;
}
inorder(root.left);
list.add(root.val);
inorder(root.right);
}
}
/**
* Definition for a binary tree node.
* public class TreeNode {
* int val;
* TreeNode left;
* TreeNode right;
* TreeNode() {}
* TreeNode(int val) { this.val = val; }
* TreeNode(int val, TreeNode left, TreeNode right) {
* this.val = val;
* this.left = left;
* this.right = right;
* }
* }
*/
class Solution {
int ans = Integer.MAX_VALUE;
TreeNode pre = null;
public int getMinimumDifference(TreeNode root) {
inorder(root);
return ans;
}
public void inorder(TreeNode root){
if(root == null){
return;
}
inorder(root.left);
if(pre != null){
ans = Math.min(ans,(root.val-pre.val));
}
pre = root;
inorder(root.right);
}
}
2.31 501. 二叉搜索树中的众数
给定一个有相同值的二叉搜索树(BST),找出 BST 中的所有众数(出现频率最高的元素)。
假定 BST 有如下定义:
结点左子树中所含结点的值小于等于当前结点的值
结点右子树中所含结点的值大于等于当前结点的值
左子树和右子树都是二叉搜索树
提示:如果众数超过1个,不需考虑输出顺序
进阶:你可以不使用额外的空间吗?(假设由递归产生的隐式调用栈的开销不被计算在内)
/**
* Definition for a binary tree node.
* public class TreeNode {
* int val;
* TreeNode left;
* TreeNode right;
* TreeNode() {}
* TreeNode(int val) { this.val = val; }
* TreeNode(int val, TreeNode left, TreeNode right) {
* this.val = val;
* this.left = left;
* this.right = right;
* }
* }
*/
class Solution {
List<Integer> answer = new ArrayList<Integer>();
int base, count, maxCount;
public int[] findMode(TreeNode root) {
dfs(root);
int[] mode = new int[answer.size()];
for (int i = 0; i < answer.size(); ++i) {
mode[i] = answer.get(i);
}
return mode;
}
public void dfs(TreeNode o) {
if (o == null) {
return;
}
dfs(o.left);
update(o.val);
dfs(o.right);
}
public void update(int x) {
if (x == base) {
++count;
} else {
count = 1;
base = x;
}
if (count == maxCount) {
answer.add(base);
}
if (count > maxCount) {
maxCount = count;
answer.clear();
answer.add(base);
}
}
}
class Solution {
ArrayList<Integer> resList;
int maxCount;
int count;
TreeNode pre;
public int[] findMode(TreeNode root) {
resList = new ArrayList<>();
maxCount = 0;
count = 0;
pre = null;
findMode1(root);
int[] res = new int[resList.size()];
for (int i = 0; i < resList.size(); i++) {
res[i] = resList.get(i);
}
return res;
}
public void findMode1(TreeNode root) {
if (root == null) {
return;
}
findMode1(root.left);
int rootValue = root.val;
// 计数
if (pre == null || rootValue != pre.val) {
count = 1;
} else {
count++;
}
// 更新结果以及maxCount
if (count > maxCount) {
resList.clear();
resList.add(rootValue);
maxCount = count;
} else if (count == maxCount) {
resList.add(rootValue);
}
pre = root;
findMode1(root.right);
}
}
2.32 236. 二叉树的最近公共祖先
给定一个二叉树, 找到该树中两个指定节点的最近公共祖先。
百度百科中最近公共祖先的定义为:“对于有根树 T 的两个节点 p、q,最近公共祖先表示为一个节点 x,满足 x 是 p、q 的祖先且 x 的深度尽可能大(一个节点也可以是它自己的祖先)。”
树中节点数目在范围 [2, 105] 内。
-109 <= Node.val <= 109
所有 Node.val 互不相同 。
p != q
p 和 q 均存在于给定的二叉树中。
/**
* Definition for a binary tree node.
* public class TreeNode {
* int val;
* TreeNode left;
* TreeNode right;
* TreeNode(int x) { val = x; }
* }
*/
class Solution {
public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) {
if(root == null){
return root;
}
if(root == p || root == q){
return root;
}
TreeNode left = lowestCommonAncestor(root.left,p,q);
TreeNode right = lowestCommonAncestor(root.right,p,q);
if(left != null && right !=null){
return root;
}
if(left == null){
return right;
}
if(right == null){
return left;
}
return null;
}
}
2.33 235. 二叉搜索树的最近公共祖先
给定一个二叉搜索树, 找到该树中两个指定节点的最近公共祖先。
百度百科中最近公共祖先的定义为:“对于有根树 T 的两个结点 p、q,最近公共祖先表示为一个结点 x,满足 x 是 p、q 的祖先且 x 的深度尽可能大(一个节点也可以是它自己的祖先)。”
例如,给定如下二叉搜索树: root = [6,2,8,0,4,7,9,null,null,3,5]
所有节点的值都是唯一的。
p、q 为不同节点且均存在于给定的二叉搜索树中。
/**
* Definition for a binary tree node.
* public class TreeNode {
* int val;
* TreeNode left;
* TreeNode right;
* TreeNode(int x) { val = x; }
* }
*/
//递归
class Solution {
public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) {
if(root == null){
return root;
}
if(root == p || root == q){
return root;
}
TreeNode left = lowestCommonAncestor(root.left,p,q);
TreeNode right = lowestCommonAncestor(root.right,p,q);
if(left != null && right !=null){
return root;
}
if(left == null){
return right;
}
if(right == null){
return left;
}
return null;
}
}
//递归:利用二叉搜索树的特性
class Solution {
public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) {
if(root == null){
return null;
}
if(root.val > p.val && root.val > q.val){
return lowestCommonAncestor(root.left,p,q);
}
if(root.val < p.val && root.val < q.val){
return lowestCommonAncestor(root.right,p,q);
}
return root;
}
}
//迭代
class Solution {
public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) {
TreeNode ancestor = root;
while (true) {
if (p.val < ancestor.val && q.val < ancestor.val) {
ancestor = ancestor.left;
} else if (p.val > ancestor.val && q.val > ancestor.val) {
ancestor = ancestor.right;
} else {
break;
}
}
return ancestor;
}
}
2.34 701. 二叉搜索树中的插入操作
给定二叉搜索树(BST)的根节点和要插入树中的值,将值插入二叉搜索树。 返回插入后二叉搜索树的根节点。 输入数据 保证 ,新值和原始二叉搜索树中的任意节点值都不同。
注意,可能存在多种有效的插入方式,只要树在插入后仍保持为二叉搜索树即可。 你可以返回 任意有效的结果 。
给定的树上的节点数介于 0 和 10^4 之间
每个节点都有一个唯一整数值,取值范围从 0 到 10^8
-10^8 <= val <= 10^8
新值和原始二叉搜索树中的任意节点值都不同
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/insert-into-a-binary-search-tree
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
/**
* Definition for a binary tree node.
* public class TreeNode {
* int val;
* TreeNode left;
* TreeNode right;
* TreeNode() {}
* TreeNode(int val) { this.val = val; }
* TreeNode(int val, TreeNode left, TreeNode right) {
* this.val = val;
* this.left = left;
* this.right = right;
* }
* }
*/
//递归
class Solution {
public TreeNode insertIntoBST(TreeNode root, int val) {
if(root == null){
TreeNode node = new TreeNode(val);
return node;
}
if(root.val > val) root.left = insertIntoBST(root.left,val);
if(root.val < val) root.right = insertIntoBST(root.right,val);
return root;
}
}
//迭代
class Solution {
public TreeNode insertIntoBST(TreeNode root, int val) {
if (root == null) {
return new TreeNode(val);
}
TreeNode pos = root;
while (pos != null) {
if (val < pos.val) {
if (pos.left == null) {
pos.left = new TreeNode(val);
break;
} else {
pos = pos.left;
}
} else {
if (pos.right == null) {
pos.right = new TreeNode(val);
break;
} else {
pos = pos.right;
}
}
}
return root;
}
}
2.35 450. 删除二叉搜索树中的节点
给定一个二叉搜索树的根节点 root 和一个值 key,删除二叉搜索树中的 key 对应的节点,并保证二叉搜索树的性质不变。返回二叉搜索树(有可能被更新)的根节点的引用。
一般来说,删除节点可分为两个步骤:
首先找到需要删除的节点;
如果找到了,删除它。
节点数的范围 [0, 104].
-105 <= Node.val <= 105
节点值唯一
root 是合法的二叉搜索树
-105 <= key <= 105
/**
* Definition for a binary tree node.
* public class TreeNode {
* int val;
* TreeNode left;
* TreeNode right;
* TreeNode() {}
* TreeNode(int val) { this.val = val; }
* TreeNode(int val, TreeNode left, TreeNode right) {
* this.val = val;
* this.left = left;
* this.right = right;
* }
* }
*/
/**
* Definition for a binary tree node.
* public class TreeNode {
* int val;
* TreeNode left;
* TreeNode right;
* TreeNode() {}
* TreeNode(int val) { this.val = val; }
* TreeNode(int val, TreeNode left, TreeNode right) {
* this.val = val;
* this.left = left;
* this.right = right;
* }
* }
*/
class Solution {
public TreeNode deleteNode(TreeNode root, int key) {
if (root == null) return null;
if (root.val > key) {
root.left = deleteNode(root.left,key);
} else if (root.val < key) {
root.right = deleteNode(root.right,key);
} else {
if (root.left == null) return root.right;
if (root.right == null) return root.left;
TreeNode tmp = root.right;
while (tmp.left != null) {
tmp = tmp.left;
}
root.val = tmp.val;
root.right = deleteNode(root.right,tmp.val);
}
return root;
}
}
2.36 669. 修剪二叉搜索树
给你二叉搜索树的根节点 root ,同时给定最小边界low 和最大边界 high。通过修剪二叉搜索树,使得所有节点的值在[low, high]中。修剪树不应该改变保留在树中的元素的相对结构(即,如果没有被移除,原有的父代子代关系都应当保留)。 可以证明,存在唯一的答案。
所以结果应当返回修剪好的二叉搜索树的新的根节点。注意,根节点可能会根据给定的边界发生改变。
树中节点数在范围 [1, 104] 内
0 <= Node.val <= 104
树中每个节点的值都是唯一的
题目数据保证输入是一棵有效的二叉搜索树
0 <= low <= high <= 104
/**
* Definition for a binary tree node.
* public class TreeNode {
* int val;
* TreeNode left;
* TreeNode right;
* TreeNode() {}
* TreeNode(int val) { this.val = val; }
* TreeNode(int val, TreeNode left, TreeNode right) {
* this.val = val;
* this.left = left;
* this.right = right;
* }
* }
*/
class Solution {
public TreeNode trimBST(TreeNode root, int low, int high) {
if(root == null){
return null;
}
if(root.val < low) return trimBST(root.right,low,high);
if(root.val > high) return trimBST(root.left,low,high);
root.left = trimBST(root.left,low,high);
root.right = trimBST(root.right,low,high);
return root;
}
}
2.37 108. 将有序数组转换为二叉搜索树
给你一个整数数组 nums ,其中元素已经按 升序 排列,请你将其转换为一棵 高度平衡 二叉搜索树。
高度平衡 二叉树是一棵满足「每个节点的左右两个子树的高度差的绝对值不超过 1 」的二叉树。
1 <= nums.length <= 104
-104 <= nums[i] <= 104
nums 按 严格递增 顺序排列
/**
* Definition for a binary tree node.
* public class TreeNode {
* int val;
* TreeNode left;
* TreeNode right;
* TreeNode() {}
* TreeNode(int val) { this.val = val; }
* TreeNode(int val, TreeNode left, TreeNode right) {
* this.val = val;
* this.left = left;
* this.right = right;
* }
* }
*/
class Solution {
public TreeNode sortedArrayToBST(int[] nums) {
return construct(nums,0,nums.length-1);
}
public TreeNode construct(int[] nums,int l,int r){
if(l > r){
return null;
}
int mid = l + (r-l)/2;
TreeNode root = new TreeNode(nums[mid]);
root.left = construct(nums,l,mid-1);
root.right = construct(nums,mid+1,r);
return root;
}
}
2.38 538. 把二叉搜索树转换为累加树
给出二叉 搜索 树的根节点,该树的节点值各不相同,请你将其转换为累加树(Greater Sum Tree),使每个节点 node 的新值等于原树中大于或等于 node.val 的值之和。
提醒一下,二叉搜索树满足下列约束条件:
节点的左子树仅包含键 小于 节点键的节点。
节点的右子树仅包含键 大于 节点键的节点。
左右子树也必须是二叉搜索树。
树中的节点数介于 0 和 104 之间。
每个节点的值介于 -104 和 104 之间。
树中的所有值 互不相同 。
给定的树为二叉搜索树。
/**
* Definition for a binary tree node.
* public class TreeNode {
* int val;
* TreeNode left;
* TreeNode right;
* TreeNode() {}
* TreeNode(int val) { this.val = val; }
* TreeNode(int val, TreeNode left, TreeNode right) {
* this.val = val;
* this.left = left;
* this.right = right;
* }
* }
*/
class Solution {
int sum = 0;
public TreeNode convertBST(TreeNode root) {
if(root == null){
return null;
}
convertBST(root.right);
sum += root.val;
root.val = sum;
convertBST(root.left);
return root;
}
}
2.39 2096. 从二叉树一个节点到另一个节点每一步的方向
给你一棵 二叉树 的根节点 root ,这棵二叉树总共有 n 个节点。每个节点的值为 1 到 n 中的一个整数,且互不相同。给你一个整数 startValue ,表示起点节点 s 的值,和另一个不同的整数 destValue ,表示终点节点 t 的值。
请找到从节点 s 到节点 t 的 最短路径 ,并以字符串的形式返回每一步的方向。每一步用 大写 字母 ‘L’ ,‘R’ 和 ‘U’ 分别表示一种方向:
‘L’ 表示从一个节点前往它的 左孩子 节点。
‘R’ 表示从一个节点前往它的 右孩子 节点。
‘U’ 表示从一个节点前往它的 父 节点。
请你返回从 s 到 t 最短路径 每一步的方向。
树中节点数目为 n 。
2 <= n <= 105
1 <= Node.val <= n
树中所有节点的值 互不相同 。
1 <= startValue, destValue <= n
startValue != destValue
/**
* Definition for a binary tree node.
* public class TreeNode {
* int val;
* TreeNode left;
* TreeNode right;
* TreeNode() {}
* TreeNode(int val) { this.val = val; }
* TreeNode(int val, TreeNode left, TreeNode right) {
* this.val = val;
* this.left = left;
* this.right = right;
* }
* }
*/
class Solution {
StringBuilder path = new StringBuilder();
public String getDirections(TreeNode root, int startValue, int destValue) {
TreeNode lowestRoot = lowestCommonAncestor(root,startValue,destValue);
findStartValue(lowestRoot,startValue);
findDestValue(lowestRoot,destValue);
return path.toString();
}
//寻找最近公共祖先
private TreeNode lowestCommonAncestor(TreeNode root,int p,int q){
if(root == null) return root;
if(root.val == p || root.val == q) return root;
TreeNode left = lowestCommonAncestor(root.left,p,q);
TreeNode right = lowestCommonAncestor(root.right,p,q);
if(left != null && right != null) return root;
if(left == null) return right;
if(right == null) return left;
return null;
}
//寻找startValue
private boolean findStartValue(TreeNode root,int startValue){
if(root == null) return false;
if(root.val == startValue) return true;
path.append("U");
if(findStartValue(root.left,startValue)) return true;
else path.deleteCharAt(path.length()-1);
path.append("U");
if(findStartValue(root.right,startValue)) return true;
else path.deleteCharAt(path.length()-1);
return false;
}
//寻找destValue
private boolean findDestValue(TreeNode root,int destValue){
if(root == null) return false;
if(root.val == destValue) return true;
path.append("L");
if(findDestValue(root.left,destValue)) return true;
else path.deleteCharAt(path.length()-1);
path.append("R");
if(findDestValue(root.right,destValue)) return true;
else path.deleteCharAt(path.length()-1);
return false;
}
}
2.40 剑指 Offer 26. 树的子结构
输入两棵二叉树A和B,判断B是不是A的子结构。(约定空树不是任意一个树的子结构)
B是A的子结构, 即 A中有出现和B相同的结构和节点值。
0 <= 节点个数 <= 10000
/**
* Definition for a binary tree node.
* public class TreeNode {
* int val;
* TreeNode left;
* TreeNode right;
* TreeNode(int x) { val = x; }
* }
*/
class Solution {
public boolean isSubStructure(TreeNode A, TreeNode B) {
if (A == null || B == null) return false;
/*
存在三种情况:
以结点A为根节点的子树和树B匹配
以结点A的左子节点为根节点的子树和树B匹配
以结点A的右子节点为根节点的子树和树B匹配
*/
boolean root = check(A,B);
boolean left = isSubStructure(A.left,B);
boolean right = isSubStructure(A.right,B);
return root || left || right;
}
//检查以A为根节点的子树是否和B树匹配
private boolean check(TreeNode A, TreeNode B) {
if (B == null) return true; // 说明B已经匹配完成
if (A == null || A.val != B.val) return false;// 说明匹配失败
return check(A.left, B.left) && check(A.right, B.right);
}
}