二叉树定义
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| class Solution { 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; } } }
|
三种递归遍历方法
递归三部曲
1 2 3
| 1.确定递归函数的参数和返回值 2.确定终止条件 3.确定单层递归的逻辑
|
三种遍历方法的左中右顺序:左右保持不变
“前/中/后”序遍历表示的是根(中)节点在三者中的位置
前序遍历:中->左->右
中序遍历:左->中->右
后序遍历:左->右->中
二叉树的前序遍历
给你二叉树的根节点 root ,返回它节点值的 前序 遍历。
https://leetcode.cn/problems/binary-tree-preorder-traversal/
代码
1 2 3 4 5 6 7 8 9 10 11 12 13
| class Solution { public List<Integer> preorderTraversal(TreeNode root) { List<Integer> list=new ArrayList(); order(root,list); return list; } public void order(TreeNode root,List<Integer> list){ if(root==null) return; list.add(root.val); order(root.left,list); order(root.right,list); } }
|
二叉树的中序遍历
给定一个二叉树的根节点 root ,返回 它的 中序 遍历 。
https://leetcode.cn/problems/binary-tree-inorder-traversal/
代码
1 2 3 4 5 6 7 8 9 10 11 12 13
| class Solution { public List<Integer> inorderTraversal(TreeNode root) { List<Integer> list=new ArrayList(); order(root,list); return list; } public void order(TreeNode root,List<Integer> list){ if(root==null) return; order(root.left,list); list.add(root.val); order(root.right,list); } }
|
二叉树的后序遍历
给你一棵二叉树的根节点 root ,返回其节点值的 后序遍历 。
https://leetcode.cn/problems/binary-tree-postorder-traversal/
代码
1 2 3 4 5 6 7 8 9 10 11 12 13
| class Solution { public List<Integer> postorderTraversal(TreeNode root) { List<Integer> list=new ArrayList(); order(root,list); return list; } public void order(TreeNode root,List<Integer> list){ if(root==null) return; order(root.left,list); order(root.right,list); list.add(root.val); } }
|
迭代遍历方法
前序遍历代码
1 2 3 4 5 6 7
| 前序遍历顺序:中-左-右,入栈顺序:中-右-左 出栈顺序:中-左-右 对每一个根节点: 1.打印值 2.向左下方遍历,遍历节点入栈,找到它的左子树最下边 3.弹出栈顶 4.其右子树为新的根节点 重复上述步骤直到栈空
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31
| class Solution { public List<Integer> preorderTraversal(TreeNode root) { List<Integer> result = new ArrayList<>(); if (root == null){ return result; } Stack<TreeNode> stack = new Stack<>(); stack.push(root); while (!stack.isEmpty()){ TreeNode node = stack.pop(); result.add(node.val); if (node.right != null){ stack.push(node.right); } if (node.left != null){ stack.push(node.left); } } return result; } }
|
中序遍历代码
1 2 3 4 5 6
| 中序遍历顺序: 左-中-右 入栈顺序: 左-右 对每一个根节点: 1.向左下方遍历,遍历节点入栈,找到它的左子树最下边 2.弹出栈顶并打印 3.其右子树为新的根节点 重复上述步骤直到栈空
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29
| class Solution { public List<Integer> inorderTraversal(TreeNode root) { List<Integer> result = new ArrayList<>(); if (root == null){ return result; } Stack<TreeNode> stack = new Stack<>(); TreeNode cur = root; while (cur != null || !stack.isEmpty()){ if (cur != null){ stack.push(cur); cur = cur.left; }else{ cur = stack.pop(); result.add(cur.val); cur = cur.right; } } return result; } }
|
后序遍历代码
1 2 3 4 5 6 7
| 后序遍历顺序 左-右-中 入栈顺序:中-左-右 出栈顺序:中-右-左, 最后翻转结果 对每一个根节点: 1.向左下方遍历,遍历节点入栈,找到它的左子树最下边 2.如果无右子树或者右子树刚被访问,直接打印根节点 否则根节点再次入栈,先处理右子树 3.其右子树为新的根节点 重复上述步骤直到栈空
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33
| class Solution { public List<Integer> postorderTraversal(TreeNode root) { List<Integer> result = new ArrayList<>(); if (root == null){ return result; } Stack<TreeNode> stack = new Stack<>(); stack.push(root); while (!stack.isEmpty()){ TreeNode node = stack.pop(); result.add(node.val); if (node.left != null){ stack.push(node.left); } if (node.right != null){ stack.push(node.right); } } Collections.reverse(result); return result; } }
|
统一风格迭代方法
前序遍历
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
| class Solution { public List<Integer> preorderTraversal(TreeNode root) { List<Integer> result = new LinkedList<>(); Stack<TreeNode> st = new Stack<>(); if (root != null) st.push(root); while (!st.empty()) { TreeNode node = st.peek(); if (node != null) { st.pop(); if (node.right!=null) st.push(node.right); if (node.left!=null) st.push(node.left); st.push(node); st.push(null); } else { st.pop(); node = st.peek(); st.pop(); result.add(node.val); } } return result; } }
|
中序遍历
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
| class Solution { public List<Integer> inorderTraversal(TreeNode root) { List<Integer> result = new LinkedList<>(); Stack<TreeNode> st = new Stack<>(); if (root != null) st.push(root); while (!st.empty()) { TreeNode node = st.peek(); if (node != null) { st.pop(); if (node.right!=null) st.push(node.right); st.push(node); st.push(null);
if (node.left!=null) st.push(node.left); } else { st.pop(); node = st.peek(); st.pop(); result.add(node.val); } } return result; } }
|
后序遍历
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
| class Solution { public List<Integer> postorderTraversal(TreeNode root) { List<Integer> result = new LinkedList<>(); Stack<TreeNode> st = new Stack<>(); if (root != null) st.push(root); while (!st.empty()) { TreeNode node = st.peek(); if (node != null) { st.pop(); st.push(node); st.push(null); if (node.right!=null) st.push(node.right); if (node.left!=null) st.push(node.left); } else { st.pop(); node = st.peek(); st.pop(); result.add(node.val); } } return result; } }
|
二叉树的层序遍历
给你二叉树的根节点 root ,返回其节点值的 层序遍历 。 (即逐层地,从左到右访问所有节点)。
https://leetcode.cn/problems/binary-tree-level-order-traversal/
思路
1 2 3 4 5 6 7 8 9 10 11 12
| 1.创建一个空的 List,用于存储层序遍历的结果。 2.如果根节点为空,直接返回空的 List(因为树为空,不存在遍历结果)。 3.创建一个队列,用于存储遍历过程中的节点。首先将根节点入队。 4.当队列不为空时,记录当前层的节点个数 size,初始值为队列中的节点个数。 5.在处理队列中的节点时,每取出一个节点,就将 size 变量减 1。 6.将取出的节点的值加入当前层的遍历结果列表中。 7.如果取出的节点的左子节点不为空,将其左子节点入队。 8.如果取出的节点的右子节点不为空,将其右子节点入队。 9.当 size 变量的值为 0 时,说明当前层的所有节点都已经处理完毕,可以进入下一层的遍历了。 10.将当前层的遍历结果列表加入到总的遍历结果列表中。 11.进入下一层的遍历,重复步骤 4-10,直到遍历完整棵树。 12.返回遍历结果列表。
|
代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40
| class Solution { public List<List<Integer>> levelOrder(TreeNode root) { List<List<Integer>> result = new ArrayList<>(); if (root == null) { return result; } Queue<TreeNode> queue = new LinkedList<>(); queue.add(root); while (!queue.isEmpty()) { int size = queue.size(); List<Integer> list = new ArrayList(); while (size-- > 0) { TreeNode node = queue.poll(); list.add(node.val); if (node.left != null) { queue.add(node.left); } if (node.right != null) { queue.add(node.right); } } result.add(list); } return result; } }
|
二叉树的层序遍历 II
给你二叉树的根节点 root ,返回其节点值 自底向上的层序遍历 。 (即按从叶子节点所在层到根节点所在的层,逐层从左向右遍历)
https://leetcode.cn/problems/binary-tree-level-order-traversal/
思路
代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| class Solution { public List<List<Integer>> levelOrderBottom(TreeNode root) { List<List<Integer>> result=new ArrayList<List<Integer>>(); if(root==null) return result; Queue<TreeNode> que=new LinkedList<>(); que.add(root); while(!que.isEmpty()){ int size=que.size(); List<Integer> list=new ArrayList<>(); while(size-->0){ TreeNode node=que.poll(); list.add(node.val); if(node.left!=null) que.add(node.left); if(node.right!=null) que.add(node.right); } result.add(list); } Collections.reverse(result); return result; } }
|
二叉树的右视图
给定一个二叉树的 根节点 root,想象自己站在它的右侧,按照从顶部到底部的顺序,返回从右侧所能看到的节点值。
https://leetcode.cn/problems/binary-tree-right-side-view/
1 2
| 输入: [1,2,3,null,5,null,4] 输出: [1,3,4]
|
思路
代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| class Solution { public List<Integer> rightSideView(TreeNode root) { List<Integer> result=new ArrayList<>(); if(root==null) return result; Queue<TreeNode> que=new LinkedList<>(); que.add(root); while(!que.isEmpty()){ int size=que.size(); List<Integer> list=new ArrayList<>(); while(size-->0){ TreeNode node=que.poll(); if(size==0) result.add(node.val); if(node.left!=null) que.add(node.left); if(node.right!=null) que.add(node.right); } } return result; } }
|
二叉树的层平均值
给定一个非空二叉树的根节点 root , 以数组的形式返回每一层节点的平均值。与实际答案相差 10-5 以内的答案可以被接受。
https://leetcode.cn/problems/average-of-levels-in-binary-tree/
思路
代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| class Solution { public List<Double> averageOfLevels(TreeNode root) { List<Double> result=new ArrayList<>(); if(root==null) return result; Queue<TreeNode> que=new LinkedList<>(); que.add(root); while(!que.isEmpty()){ int size=que.size(); int tmp=size; double sum=0; while(tmp-->0){ TreeNode node=que.poll(); sum+=node.val; if(node.left!=null) que.add(node.left); if(node.right!=null) que.add(node.right); } result.add(sum/size); } return result; } }
|
N 叉树的层序遍历
给定一个 N 叉树,返回其节点值的层序遍历。(即从左到右,逐层遍历)。
树的序列化输入是用层序遍历,每组子节点都由 null 值分隔(参见示例)。
https://leetcode.cn/problems/n-ary-tree-level-order-traversal/
示例
思路
代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| class Solution { public List<List<Integer>> levelOrder(Node root) { List<List<Integer>> result=new ArrayList<>(); if(root==null) return result; Queue<Node> que=new LinkedList<>(); que.add(root); while(!que.isEmpty()){ int size=que.size(); List<Integer> list=new ArrayList<>(); while(size-->0){ Node node=que.poll(); list.add(node.val); for(Node child : node.children){ que.add(child); } } result.add(list); } return result; } }
|
在每个树行中找最大值
给定一棵二叉树的根节点 root ,请找出该二叉树中每一层的最大值。
https://leetcode.cn/problems/find-largest-value-in-each-tree-row/
思路
代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| class Solution { public List<Integer> largestValues(TreeNode root) { List<Integer> result=new ArrayList<>(); if(root==null) return result; Queue<TreeNode> que=new LinkedList<>(); que.add(root); while(!que.isEmpty()){ int size=que.size(); int max=Integer.MIN_VALUE; while(size-->0){ TreeNode node=que.poll(); max=node.val>max?node.val:max; if(node.left!=null) que.add(node.left); if(node.right!=null) que.add(node.right); } result.add(max); } return result; } }
|
填充每个节点的下一个右侧节点指针
给定一个 完美二叉树 ,其所有叶子节点都在同一层,每个父节点都有两个子节点。二叉树定义如下:
1 2 3 4 5 6
| struct Node { int val; Node *left; Node *right; Node *next; }
|
填充它的每个 next 指针,让这个指针指向其下一个右侧节点。如果找不到下一个右侧节点,则将 next 指针设置为 NULL。
初始状态下,所有 next 指针都被设置为 NULL。
https://leetcode.cn/problems/populating-next-right-pointers-in-each-node
思路
代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| class Solution { public Node connect(Node root) { if(root==null) return root; Queue<Node> que=new LinkedList<>(); que.add(root); while(!que.isEmpty()){ int size=que.size(); Node prev=null; while(size-->0){ Node node=que.poll(); if(prev!=null) prev.next=node; prev=node; if(node.left!=null) que.add(node.left); if(node.right!=null) que.add(node.right); } } return root; } }
|
填充每个节点的下一个右侧节点指针 II
给定一个二叉树:
1 2 3 4 5 6
| struct Node { int val; Node *left; Node *right; Node *next; }
|
填充它的每个 next 指针,让这个指针指向其下一个右侧节点。如果找不到下一个右侧节点,则将 next 指针设置为 NULL 。
初始状态下,所有 next 指针都被设置为 NULL 。
https://leetcode.cn/problems/populating-next-right-pointers-in-each-node-ii
思路
代码
同上
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| class Solution { public Node connect(Node root) { if(root==null) return root; Queue<Node> que=new LinkedList<>(); que.add(root); while(!que.isEmpty()){ int size=que.size(); Node prev=null; while(size-->0){ Node node=que.poll(); if(prev!=null) prev.next=node; prev=node; if(node.left!=null) que.add(node.left); if(node.right!=null) que.add(node.right); } } return root; } }
|
二叉树的最大深度
给定一个二叉树,找出其最大深度。
二叉树的深度为根节点到最远叶子节点的最长路径上的节点数。
说明: 叶子节点是指没有子节点的节点。
示例
1 2
| 给定二叉树 [3,9,20,null,null,15,7] 返回它的最大深度 3
|
https://leetcode.cn/problems/maximum-depth-of-binary-tree
思路
代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| class Solution { public int maxDepth(TreeNode root) { if(root==null) return 0; int depth=0; Queue<TreeNode> que=new LinkedList<>(); que.add(root); while(!que.isEmpty()){ int size=que.size(); while(size-->0){ TreeNode node= que.poll(); if(size==0) depth++; if(node.left!=null) que.add(node.left); if(node.right!=null) que.add(node.right); } } return depth; } }
|
二叉树的最小深度
给定一个二叉树,找出其最小深度。
最小深度是从根节点到最近叶子节点的最短路径上的节点数量。
说明:叶子节点是指没有子节点的节点。
https://leetcode.cn/problems/minimum-depth-of-binary-tree/
思路
代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| class Solution { public int minDepth(TreeNode root) { if(root==null) return 0; int depth=0; Queue<TreeNode> que=new LinkedList<>(); que.add(root); while(!que.isEmpty()){ int size=que.size(); while(size-->0){ TreeNode node= que.poll(); if(node.left==null && node.right==null) return depth+1; if(size==0) depth++; if(node.left!=null) que.add(node.left); if(node.right!=null) que.add(node.right); } } return depth; } }
|
翻转二叉树
给你一棵二叉树的根节点 root ,翻转这棵二叉树,并返回其根节点。
https://leetcode.cn/problems/invert-binary-tree/
思路
代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| class Solution { public TreeNode invertTree(TreeNode root) { invertNode(root); return root; } public void invertNode(TreeNode node){ if(node==null) return; TreeNode tmp=node.left; node.left=node.right; node.right=tmp; invertNode(node.left); invertNode(node.right); } }
|
对称二叉树
给你一个二叉树的根节点 root , 检查它是否轴对称。
https://leetcode.cn/problems/symmetric-tree/
思路
1 2
| 1.写一个函数比较两个节点是否对称 2.递归遍历
|
代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| class Solution { public boolean isSymmetric(TreeNode root) { if (root == null) { return true; } return check(root.left, root.right); }
public boolean check(TreeNode p, TreeNode q) { if (p == null && q == null) { return true; } if (p == null || q == null || p.val != q.val) { return false; } return check(p.left, q.right) && check(p.right, q.left); } }
|
相同的树
给你两棵二叉树的根节点 p 和 q ,编写一个函数来检验这两棵树是否相同。
如果两个树在结构上相同,并且节点具有相同的值,则认为它们是相同的。
https://leetcode.cn/problems/same-tree/
思路
1 2
| 1.写一个函数比较两个节点是否对称 2.递归遍历
|
代码
1 2 3 4 5 6 7
| class Solution { public boolean isSameTree(TreeNode p, TreeNode q) { if(p==null && q==null) return true; if(p==null || q==null || p.val!=q.val) return false; return isSameTree(p.left,q.left) && isSameTree(p.right,q.right); } }
|
另一棵树的子树
给你两棵二叉树 root 和 subRoot 。检验 root 中是否包含和 subRoot 具有相同结构和节点值的子树。如果存在,返回 true ;否则,返回 false 。
二叉树 tree 的一棵子树包括 tree 的某个节点和这个节点的所有后代节点。tree 也可以看做它自身的一棵子树。
https://leetcode.cn/problems/subtree-of-another-tree
思路
1 2
| 1.dfs函数用于递归遍历s的子树 2.check函数用于检查s和t在当前节点是否相等
|
代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
| 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); } }
|
完全二叉树的节点个数
给你一棵 完全二叉树 的根节点 root ,求出该树的节点个数。
完全二叉树 的定义如下:在完全二叉树中,除了最底层节点可能没填满外,其余每层节点数都达到最大值,并且最下面一层的节点都集中在该层最左边的若干位置。若最底层为第 h 层,则该层包含 1~ 2h 个节点。
https://leetcode.cn/problems/count-complete-tree-nodes
思路
代码
1 2 3 4 5 6 7 8 9 10 11 12 13
| class Solution { public int countNodes(TreeNode root) { int size=0; return count(root,size); } public int count(TreeNode node,int size){ if(node==null) return size; else size++; if(node.left!=null) size=count(node.left,size); if(node.right!=null) size=count(node.right,size); return size; } }
|
平衡二叉树
给定一个二叉树,判断它是否是高度平衡的二叉树。
本题中,一棵高度平衡二叉树定义为:
一个二叉树每个节点 的左右两个子树的高度差的绝对值不超过 1 。
https://leetcode.cn/problems/balanced-binary-tree/
思路
1 2
| 1.isBalanced() 方法通过递归判断左右子树的高度差是否不超过 1,并且左右子树也都是高度平衡的,来判断当前二叉树是否为高度平衡的二叉树 2.height() 方法用于计算二叉树的高度。该方法通过递归计算左右子树的高度,并取其中的最大值加 1,来计算当前节点的高度。
|
代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| 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); }
public int height(TreeNode root) { if (root == null) { return 0; } return Math.max(height(root.left), height(root.right)) + 1; } }
|
二叉树的所有路径
给你一个二叉树的根节点 root ,按 任意顺序 ,返回所有从根节点到叶子节点的路径。
叶子节点 是指没有子节点的节点。
示例
1 2 3 4
| 输入:root = [1,2,3,null,5] 输出:["1->2->5","1->3"] 输入:root = [1] 输出:["1"]
|
https://leetcode.cn/problems/binary-tree-paths/
思路
1 2 3
| 1.dfs 方法中,首先判断当前节点是否为叶子节点,如果是,则将访问过的路径添加到 res 列表中,并返回。
否则,对当前节点的左右子节点进行递归搜索,并在搜索过程中,将访问过的路径拼接起来
|
代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26
| class Solution { public List<String> binaryTreePaths(TreeNode root) { List<String> res = new ArrayList<>(); if (root == null) { return res; } dfs(root, "", res); return res; }
private void dfs(TreeNode node, String path, List<String> res) { if (node.left == null && node.right == null) { res.add(path + node.val); return; } if (node.left != null) { dfs(node.left, path + node.val + "->", res); } if (node.right != null) { dfs(node.right, path + node.val + "->", res); } } }
|
左叶子之和
给定二叉树的根节点 root ,返回所有左叶子之和。
https://leetcode.cn/problems/sum-of-left-leaves/
思路
1
| 1.首先判断当前节点的左子节点是否为左叶子节点,如果是,则将该节点的值累加到 sum 中。否则,对当前节点的左右子节点进行递归搜索,并在搜索过程中,累加所有左叶子节点的值。最终返回左右子树的累加和。
|
代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| class Solution { public int sumOfLeftLeaves(TreeNode root) { if(root==null) return 0; return dfs(root,0); } public int dfs(TreeNode node,int sum){ if(node.left!=null && node.left.left==null && node.left.right==null){ sum+=node.left.val; } if(node.left!=null) sum=dfs(node.left,sum); if(node.right!=null) sum=dfs(node.right,sum); return sum; } }
|
找树左下角的值
给定一个二叉树的 根节点 root,请找出该二叉树的 最底层 最左边 节点的值。
假设二叉树中至少有一个节点。
https://leetcode.cn/problems/find-bottom-left-tree-value/
思路
代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| class Solution { public int findBottomLeftValue(TreeNode root) { List<List<Integer>> result=new ArrayList<>(); Queue<TreeNode> que=new LinkedList<>(); que.add(root); while(!que.isEmpty()){ int size=que.size(); List<Integer> list=new ArrayList<>(); while(size-->0){ TreeNode node=que.poll(); list.add(node.val); if(node.left!=null) que.add(node.left); if(node.right!=null) que.add(node.right); } result.add(list); } return result.get(result.size()-1).get(0); } }
|
路径总和
给你二叉树的根节点 root 和一个表示目标和的整数 targetSum 。判断该树中是否存在 根节点到叶子节点 的路径,这条路径上所有节点值相加等于目标和 targetSum 。如果存在,返回 true ;否则,返回 false 。
叶子节点 是指没有子节点的节点。
示例
1 2 3
| 输入:root = [5,4,8,11,null,13,4,7,2,null,null,null,1], targetSum = 22 输出:true 解释:等于目标和的根节点到叶节点路径如上图所示。
|
https://leetcode.cn/problems/path-sum
思路
1
| 1.假定从根节点到当前节点的值之和为 val,我们可以将这个大问题转化为一个小问题:是否存在从当前节点的子节点到叶子的路径,满足其路径和为 sum - val。
|
代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| class Solution { public boolean hasPathSum(TreeNode root, int sum) { if (root == null) { return false; } if (root.left == null && root.right == null) { return sum == root.val; } return hasPathSum(root.left, sum - root.val) || hasPathSum(root.right, sum - root.val); } }
|
从中序与后序遍历序列构造二叉树
给定两个整数数组 inorder 和 postorder ,其中 inorder 是二叉树的中序遍历, postorder 是同一棵树的后序遍历,请你构造并返回这颗 二叉树 。
示例
1 2
| 输入:inorder = [9,3,15,20,7], postorder = [9,15,7,20,3] 输出:[3,9,20,null,null,15,7]
|
https://leetcode.cn/problems/construct-binary-tree-from-inorder-and-postorder-traversal
思路
1 2 3 4 5 6 7 8 9 10
| 给定一棵二叉树的中序遍历数组和后序遍历数组,构造出这棵二叉树。
1.确定根节点 由于后序遍历的顺序是左子树 -> 右子树 -> 根节点,因此后序遍历数组的最后一个元素一定是根节点。在中序遍历数组中找到根节点的位置,可以将整个数组分成左子树和右子树两部分。
2.递归构造左子树和右子树 通过根节点在中序遍历数组中的位置,可以确定左子树和右子树的中序遍历数组。在后序遍历数组中,左子树和右子树的位置也可以根据左子树的长度确定。然后可以递归构造左子树和右子树,直到叶子节点为止。
3.返回根节点 将左子树和右子树递归构造出来后,就可以将根节点和左右子树连接起来,构造出整棵二叉树。最后返回根节点即可。
|
代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37
| class Solution { HashMap<Integer,Integer> inorderArrayMap = new HashMap<>(); int[] post;
public TreeNode buildTree(int[] inorder, int[] postorder) { for(int i = 0;i < inorder.length; i++) { inorderArrayMap.put(inorder[i], i); } post = postorder; TreeNode root = buildTree(0, inorder.length - 1, 0, post.length - 1); return root; }
public TreeNode buildTree(int inorderStart, int inorderEnd, int postorderStart, int postorderEnd) { if(inorderEnd < inorderStart || postorderEnd < postorderStart) return null;
int root = post[postorderEnd]; int rootIndexInInorderArray = inorderArrayMap.get(root);
TreeNode node = new TreeNode(root); node.left = buildTree(inorderStart, rootIndexInInorderArray - 1, postorderStart, postorderStart + rootIndexInInorderArray - inorderStart - 1); node.right = buildTree(rootIndexInInorderArray + 1, inorderEnd, postorderStart + rootIndexInInorderArray - inorderStart, postorderEnd - 1); return node; } }
|
最大二叉树
给定一个不重复的整数数组 nums 。 最大二叉树 可以用下面的算法从 nums 递归地构建:
创建一个根节点,其值为 nums 中的最大值。
递归地在最大值 左边 的 子数组前缀上 构建左子树。
递归地在最大值 右边 的 子数组后缀上 构建右子树。
返回 nums 构建的 最大二叉树 。
示例
1 2 3 4 5 6 7 8 9 10 11 12
| 输入:nums = 输出: 解释:递归调用如下所示: - 中的最大值是 6 ,左边部分是 ,右边部分是 。 - 中的最大值是 3 ,左边部分是 ,右边部分是 。 - 空数组,无子节点。 - 中的最大值是 2 ,左边部分是 ,右边部分是 。 - 空数组,无子节点。 - 只有一个元素,所以子节点是一个值为 1 的节点。 - 中的最大值是 5 ,左边部分是 ,右边部分是 。 - 只有一个元素,所以子节点是一个值为 0 的节点。 - 空数组,无子节点。
|
https://leetcode.cn/problems/maximum-binary-tree
思路
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| 1.定义递归函数 定义一个递归函数 constructMaximumBinaryTree(int[] nums, int start, int end),其中 nums 表示给定的数组,start 和 end 表示当前递归的数组的起始位置和终止位置。
2.找到最大值及其索引 在数组 nums 的范围 [start, end] 中找到最大值及其索引。
3.构造根节点 用最大值创建一个根节点 root。
4.递归构造左子树 将数组 nums 中范围 [start, maxIndex-1] 的部分作为一个新的子数组,递归调用 constructMaximumBinaryTree(nums, start, maxIndex-1) 方法,返回值作为当前节点的左子节点。
5.递归构造右子树 将数组 nums 中范围 [maxIndex+1, end] 的部分作为一个新的子数组,递归调用 constructMaximumBinaryTree(nums, maxIndex+1, end) 方法,返回值作为当前节点的右子节点。
6.返回根节点
|
代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28
| class Solution { public TreeNode constructMaximumBinaryTree(int[] nums) { return constructMaximumBinaryTree(nums, 0, nums.length - 1); } private TreeNode constructMaximumBinaryTree(int[] nums, int start, int end) { if (start > end) { return null; } int maxIndex = start; for (int i = start + 1; i <= end; i++) { if (nums[i] > nums[maxIndex]) { maxIndex = i; } } TreeNode root = new TreeNode(nums[maxIndex]); root.left = constructMaximumBinaryTree(nums, start, maxIndex - 1); root.right = constructMaximumBinaryTree(nums, maxIndex + 1, end); return root; } }
|
合并二叉树
给你两棵二叉树: root1 和 root2 。
想象一下,当你将其中一棵覆盖到另一棵之上时,两棵树上的一些节点将会重叠(而另一些不会)。你需要将这两棵树合并成一棵新二叉树。合并的规则是:如果两个节点重叠,那么将这两个节点的值相加作为合并后节点的新值;否则,不为 null 的节点将直接作为新二叉树的节点。
返回合并后的二叉树。
注意: 合并过程必须从两个树的根节点开始。
https://leetcode.cn/problems/merge-two-binary-trees
思路
1 2 3 4 5 6 7 8 9 10 11 12 13
| 1.定义递归函数 定义一个递归函数 mergeTrees(TreeNode root1, TreeNode root2),其中 root1 和 root2 分别表示两棵给定的二叉树。
2.处理特殊情况 如果其中一个节点为 null,则返回另一个节点。
3.合并节点值 如果两个节点都不为 null,则将它们的值相加,然后继续递归合并它们的左右子树。
4.返回合并后的根节点 递归结束后,返回合并后的根节点即可。
这个解题思路主要采用了递归的方式来合并两棵二叉树。每次递归都将原始的两个节点进行合并,并且递归合并它们的左右子树。由于每次递归都会比较左右节点的情况,因此递归深度最大为两棵树中节点数较大的一棵,时间复杂度为 $O(n)$。
|
代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26
| class Solution { public TreeNode mergeTrees(TreeNode root1, TreeNode root2) { if (root1 == null || root2 == null) { return root1 == null ? root2 : root1; } return dfs(root1, root2); }
public TreeNode dfs(TreeNode node1, TreeNode node2) { if (node1 == null || node2 == null) { return node1 == null ? node2 : node1; } node1.val += node2.val; node1.left = dfs(node1.left, node2.left); node1.right = dfs(node1.right, node2.right); return node1; } }
|
二叉搜索树中的搜索
给定二叉搜索树(BST)的根节点 root 和一个整数值 val。
你需要在 BST 中找到节点值等于 val 的节点。 返回以该节点为根的子树。 如果节点不存在,则返回 null 。
https://leetcode.cn/problems/search-in-a-binary-search-tree
思路
1 2
| 1.递归遍历搜索 2.如果target更大,在右子树中找,否则在左子树中找
|
代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| class Solution { public TreeNode searchBST(TreeNode root, int val) { if (root == null) { return null; } if (root.val == val) { return root; } else if (root.val > val) { return searchBST(root.left, val); } else { return searchBST(root.right, val); } } }
|
验证二叉搜索树
给你一个二叉树的根节点 root ,判断其是否是一个有效的二叉搜索树。
有效 二叉搜索树定义如下:
节点的左子树只包含 小于 当前节点的数。
节点的右子树只包含 大于 当前节点的数。
所有左子树和右子树自身必须也是二叉搜索树。
https://leetcode.cn/problems/validate-binary-search-tree
思路
1 2
| 1.中序遍历结果是增序,递归遍历生成list,判断list是否增序即可 2.可以用全局变量保存prev节点值,中序遍历时一旦小于等于prev,判别为false
|
代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38
| class Solution { List<Integer> result=new ArrayList<>(); public boolean isValidBST(TreeNode root) { order(root); for(int i=1;i<this.result.size();i++){ if((long)this.result.get(i)-this.result.get(i-1)<=0){ return false; } } return true; } public void order(TreeNode root){ if(root.left!=null) order(root.left); result.add(root.val); if(root.right!=null) order(root.right); } } class Solution { private Integer prev = null;
public boolean isValidBST(TreeNode root) { if (root == null) { return true; }
if (!isValidBST(root.left)) { return false; }
if (prev != null && prev >= root.val) { return false; }
prev = root.val;
return isValidBST(root.right); } }
|
二叉搜索树的最小绝对差
给你一个二叉搜索树的根节点 root ,返回 树中任意两不同节点值之间的最小差值 。
差值是一个正数,其数值等于两值之差的绝对值。
https://leetcode.cn/problems/minimum-absolute-difference-in-bst/
思路
代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| class Solution { private Integer prev=null; private int min=Integer.MAX_VALUE; public int getMinimumDifference(TreeNode root) { order(root); return min; } public void order(TreeNode root){ if(root.left!=null) order(root.left); if(prev!=null && root.val-prev<min) min=root.val-prev; prev=root.val; if(root.right!=null) order(root.right); } }
|
二叉搜索树中的众数
给你一个含重复值的二叉搜索树(BST)的根节点 root ,找出并返回 BST 中的所有 众数(即,出现频率最高的元素)。
如果树中有不止一个众数,可以按 任意顺序 返回。
假定 BST 满足如下定义:
结点左子树中所含节点的值 小于等于 当前节点的值
结点右子树中所含节点的值 大于等于 当前节点的值
左子树和右子树都是二叉搜索树
https://leetcode.cn/problems/find-mode-in-binary-search-tree
思路
1 2 3 4 5 6 7 8 9
| 1.使用中序遍历的方式遍历二叉搜索树; 2.维护四个变量:prevVal,count,maxCount 和 modes。
3.在遍历过程中,如果当前节点的值等于上一个访问的节点的值,则将 count 加 1;否则,将 count 设为 1,prevVal 设为当前节点的值。 4.如果 count 大于 maxCount,则将 maxCount 更新为 count,将 modes 清空,并将当前节点的值添加到 modes 中;如果 count 等于 maxCount,则将当前节点的值添加到 modes 中。 5.维护了所有出现次数最多的节点值,最后将这些节点值转换为数组返回即可。
|
代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40
| class Solution { private int prevVal = -1; private int count = 0; private int maxCount = 0; private List<Integer> modes = new ArrayList<>();
public int[] findMode(TreeNode root) { inorder(root); int[] result = new int[modes.size()]; for (int i = 0; i < modes.size(); i++) { result[i] = modes.get(i); } return result; }
private void inorder(TreeNode node) { if (node == null) { return; }
inorder(node.left);
if (node.val == prevVal) { count++; } else { count = 1; prevVal = node.val; }
if (count > maxCount) { maxCount = count; modes.clear(); modes.add(node.val); } else if (count == maxCount) { modes.add(node.val); }
inorder(node.right); } }
|
二叉树的最近公共祖先
给定一个二叉树, 找到该树中两个指定节点的最近公共祖先。
百度百科中最近公共祖先的定义为:“对于有根树 T 的两个节点 p、q,最近公共祖先表示为一个节点 x,满足 x 是 p、q 的祖先且 x 的深度尽可能大(一个节点也可以是它自己的祖先)。”
示例
1 2 3
| 输入:root = [3,5,1,6,2,0,8,null,null,7,4], p = 5, q = 1 输出:3 解释:节点 5 和节点 1 的最近公共祖先是节点 3 。
|
https://leetcode.cn/problems/lowest-common-ancestor-of-a-binary-tree
思路
1 2 3 4
| 1.如果p,q为根节点,则公共祖先为根节点 2.如果p,q在左子树,则公共祖先在左子树查找 3.如果p,q在右子树,则公共祖先在右子树查找 4.如果p,q分属两侧,则公共祖先为根节点
|
代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26
| 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 root; if (find(root.left, p) && find(root.left, q)) { return lowestCommonAncestor(root.left, p, q); } if (find(root.right, p) && find(root.right, q)) { return lowestCommonAncestor(root.right, p, q); } return root; } private boolean find(TreeNode root, TreeNode c) { if (root == null) return false; if (root.val == c.val) { return true; } return find(root.left, c) || find(root.right, c); } }
|
二叉搜索树的最近公共祖先
给定一个二叉搜索树, 找到该树中两个指定节点的最近公共祖先。
百度百科中最近公共祖先的定义为:“对于有根树 T 的两个结点 p、q,最近公共祖先表示为一个结点 x,满足 x 是 p、q 的祖先且 x 的深度尽可能大(一个节点也可以是它自己的祖先)。”
例如,给定如下二叉搜索树: root = [6,2,8,0,4,7,9,null,null,3,5]
https://leetcode.cn/problems/lowest-common-ancestor-of-a-binary-search-tree
思路
1 2
| 1.与上一题相比,树是有序的 2.替换find方法为val的比较
|
代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| 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 root; if (p.val<root.val && q.val<root.val) { return lowestCommonAncestor(root.left, p, q); } if (p.val>root.val && q.val>root.val) { return lowestCommonAncestor(root.right, p, q); } return root; } }
|
二叉搜索树中的插入操作
给定二叉搜索树(BST)的根节点 root 和要插入树中的值 value ,将值插入二叉搜索树。 返回插入后二叉搜索树的根节点。 输入数据 保证 ,新值和原始二叉搜索树中的任意节点值都不同。
注意,可能存在多种有效的插入方式,只要树在插入后仍保持为二叉搜索树即可。 你可以返回 任意有效的结果 。
https://leetcode.cn/problems/insert-into-a-binary-search-tree
思路
1 2 3 4
| 1.从根节点开始遍历树。 2.如果插入值大于当前节点的值,则往右子树遍历;否则,往左子树遍历。 3.如果遍历到一个空节点,则插入新节点并跳出循环。 4.返回根节点。
|
代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33
| class Solution { public TreeNode insertIntoBST(TreeNode root, int val) { if(root==null) return new TreeNode(val); TreeNode p=root; while(true){ if(val>p.val){ if(p.right==null) { p.right=new TreeNode(val); break; } else p=p.right; } else{ if(p.left==null){ p.left=new TreeNode(val); break; } else p=p.left; } } return root; } }
|
删除二叉搜索树中的节点
给定一个二叉搜索树的根节点 root 和一个值 key,删除二叉搜索树中的 key 对应的节点,并保证二叉搜索树的性质不变。返回二叉搜索树(有可能被更新)的根节点的引用。
一般来说,删除节点可分为两个步骤:
首先找到需要删除的节点;
如果找到了,删除它。
https://leetcode.cn/problems/delete-node-in-a-bst
思路
1 2 3 4 5 6 7 8 9 10 11
| 1.如果根节点为空,则返回 null。 2.如果待删除节点的值小于当前节点的值,则从左子树中删除;如果待删除节点的值大于当前节点的值,则从右子树中删除。 if(key < root.val) root.left = deleteNode(root.left, key); 3.如果找到了待删除节点,则: 如果该节点的左子树为空,则返回右子树。 如果该节点的右子树为空,则返回左子树。 如果该节点的左右子树均不为空,则: 找到右子树的最左节点。 将左子树接到右子树的最左节点的左子树上。 返回右子树。 4.返回根节点。
|
代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| class Solution { public TreeNode deleteNode(TreeNode root, int key) { if(root == null) return null; if(key < root.val) root.left = deleteNode(root.left, key); else if(key > root.val) root.right = deleteNode(root.right, key); else{ if(root.left == null) return root.right; else if(root.right == null) return root.left; TreeNode p = root.right; while(p.left != null) p = p.left; p.left = root.left; return root.right; } return root; } }
|
修剪二叉搜索树
给你二叉搜索树的根节点 root ,同时给定最小边界low 和最大边界 high。通过修剪二叉搜索树,使得所有节点的值在[low, high]中。修剪树 不应该 改变保留在树中的元素的相对结构 (即,如果没有被移除,原有的父代子代关系都应当保留)。 可以证明,存在 唯一的答案 。
所以结果应当返回修剪好的二叉搜索树的新的根节点。注意,根节点可能会根据给定的边界发生改变。
https://leetcode.cn/problems/trim-a-binary-search-tree
思路
1 2 3 4 5
| 1.如果根节点为空,则返回 null。 2.如果根节点的值大于 high,则修剪左子树。 3.如果根节点的值小于 low,则修剪右子树。 4.否则,修剪左右子树。 5.回根节点。
|
代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| class Solution { public TreeNode trimBST(TreeNode root, int low, int high) { if(root==null) return null; if(root.val>high) return trimBST(root.left,low,high); else if(root.val<low) return trimBST(root.right,low,high); else{ root.left=trimBST(root.left,low,high); root.right=trimBST(root.right,low,high); return root; } } }
|
将有序数组转换为二叉搜索树
给你一个整数数组 nums ,其中元素已经按 升序 排列,请你将其转换为一棵 高度平衡 二叉搜索树。
高度平衡 二叉树是一棵满足「每个节点的左右两个子树的高度差的绝对值不超过 1 」的二叉树。
https://leetcode.cn/problems/convert-sorted-array-to-binary-search-tree
思路
1 2 3 4 5 6 7
| 1.在类中定义一个成员变量 int[] nums,用于存储输入的有序数组。 2.在 sortedArrayToBST 方法中,将 nums 赋值为输入的有序数组,调用 build 方法构建平衡二叉搜索树并返回根节点。 3.在 build 方法中,如果起始下标大于结束下标,则返回 null。 4.找到中间位置的下标,将该位置的值作为当前节点的值。 5.递归构建左子树,起始下标为 start,结束下标为 (start+end)/2-1。 6.递归构建右子树,起始下标为 (start+end)/2+1,结束下标为 end。 7.返回当前节点。
|
代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| class Solution { int[] nums; public TreeNode sortedArrayToBST(int[] nums) { this.nums=nums; return build(0,nums.length-1); } public TreeNode build(int start,int end){ if(start>end) return null; TreeNode node= new TreeNode(nums[(start+end)/2]); node.left=build(start,(start+end)/2-1); node.right=build((start+end)/2+1,end); return node; } }
|
把二叉搜索树转换为累加树
给出二叉 搜索 树的根节点,该树的节点值各不相同,请你将其转换为累加树(Greater Sum Tree),使每个节点 node 的新值等于原树中大于或等于 node.val 的值之和。
提醒一下,二叉搜索树满足下列约束条件:
节点的左子树仅包含键 小于 节点键的节点。
节点的右子树仅包含键 大于 节点键的节点。
左右子树也必须是二叉搜索树。
https://leetcode.cn/problems/convert-bst-to-greater-tree/
思路
1
| 1.从大到小遍历,大的节点累加即可,使用递归,右中左
|
代码
1 2 3 4 5 6 7 8 9 10 11
| class Solution { private 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; } }
|