目录
101.对称二叉树
100.相同的树
572.另一棵树的子树
104.二叉树的最大深度
559.N叉树的最大深度
111.二叉树的最小深度
222.完全二叉树的节点个数
110.平衡二叉树
257.二叉树的所有路径
101.对称二叉树
101. 对称二叉树
已解答
简单
相关标签
相关企业
给你一个二叉树的根节点 root
, 检查它是否轴对称。
示例 1:
输入:root = [1,2,2,3,4,4,3]
输出:true
示例 2:
输入:root = [1,2,2,null,3,null,3]
输出:false
提示:
- 树中节点数目在范围
[1, 1000]
内 -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 boolean isSymmetric(TreeNode root) {// 调用递归函数比较左右子树return compare(root.left, root.right);}// 递归比较左右子树是否对称public boolean compare(TreeNode left, TreeNode right) {// 如果左右子节点都为空,则对称if (left == null && right == null) {return true;}// 如果左右子节点其中一个为空,另一个不为空,则不对称if (left == null || right == null) {return false;}// 如果左右子节点的值不相等,则不对称if (left.val != right.val) {return false;}// 递归比较左子节点的左子树与右子节点的右子树,以及左子节点的右子树与右子节点的左子树是否对称boolean out = compare(left.left, right.right);boolean in = compare(left.right, right.left);// 如果左右子树都对称,则整体对称return out && in;}
}
迭代法:
/*** 迭代法* 使用双端队列,相当于两个栈*/public boolean isSymmetric2(TreeNode root) {Deque<TreeNode> deque = new LinkedList<>();deque.offerFirst(root.left);deque.offerLast(root.right);while (!deque.isEmpty()) {TreeNode leftNode = deque.pollFirst();TreeNode rightNode = deque.pollLast();if (leftNode == null && rightNode == null) {continue;}
// if (leftNode == null && rightNode != null) {
// return false;
// }
// if (leftNode != null && rightNode == null) {
// return false;
// }
// if (leftNode.val != rightNode.val) {
// return false;
// }// 以上三个判断条件合并if (leftNode == null || rightNode == null || leftNode.val != rightNode.val) {return false;}deque.offerFirst(leftNode.left);deque.offerFirst(leftNode.right);deque.offerLast(rightNode.right);deque.offerLast(rightNode.left);}return true;}/*** 迭代法* 使用普通队列*/public boolean isSymmetric3(TreeNode root) {Queue<TreeNode> deque = new LinkedList<>();deque.offer(root.left);deque.offer(root.right);while (!deque.isEmpty()) {TreeNode leftNode = deque.poll();TreeNode rightNode = deque.poll();if (leftNode == null && rightNode == null) {continue;}
// if (leftNode == null && rightNode != null) {
// return false;
// }
// if (leftNode != null && rightNode == null) {
// return false;
// }
// if (leftNode.val != rightNode.val) {
// return false;
// }// 以上三个判断条件合并if (leftNode == null || rightNode == null || leftNode.val != rightNode.val) {return false;}// 这里顺序与使用Deque不同deque.offer(leftNode.left);deque.offer(rightNode.right);deque.offer(leftNode.right);deque.offer(rightNode.left);}return true;}
100.相同的树
100. 相同的树
已解答
简单
相关标签
相关企业
给你两棵二叉树的根节点 p
和 q
,编写一个函数来检验这两棵树是否相同。
如果两个树在结构上相同,并且节点具有相同的值,则认为它们是相同的。
示例 1:
输入:p = [1,2,3], q = [1,2,3]
输出:true
示例 2:
输入:p = [1,2], q = [1,null,2]
输出:false
示例 3:
输入:p = [1,2,1], q = [1,1,2]
输出:false
提示:
- 两棵树上的节点数目都在范围
[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;}// 如果左右子节点其中一个为空,另一个不为空,则不相同if (p == null || q == null) {return false;}// 如果左右子节点的值不相等,则不相同if (p.val != q.val) {return false;}// 递归比较左子节点的左子树与右子节点的右子树,以及左子节点的右子树与右子节点的左子树是否相同boolean left = isSameTree(p.left, q.left);boolean right = isSameTree(p.right, q.right);// 如果左右子树都相同,则整体相同return left && right;}
}
572.另一棵树的子树
572. 另一棵树的子树
已解答
简单
相关标签
相关企业
提示
给你两棵二叉树 root
和 subRoot
。检验 root
中是否包含和 subRoot
具有相同结构和节点值的子树。如果存在,返回 true
;否则,返回 false
。
二叉树 tree
的一棵子树包括 tree
的某个节点和这个节点的所有后代节点。tree
也可以看做它自身的一棵子树。
示例 1:
输入:root = [3,4,5,1,2], subRoot = [4,1,2]
输出:true
示例 2:
输入:root = [3,4,5,1,2,null,null,null,null,0], subRoot = [4,1,2]
输出:false
提示:
root
树上的节点数量范围是[1, 2000]
subRoot
树上的节点数量范围是[1, 1000]
-104 <= root.val <= 104
-104 <= subRoot.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 isSubtree(TreeNode root, TreeNode subRoot) {// 如果根节点为空,则返回falseif (root == null) {return false;}// 判断当前子树是否与给定子树相同,或者在左子树或右子树中是否存在相同子树return isSameTree(root, subRoot) || isSubtree(root.left, subRoot) || isSubtree(root.right, subRoot);}// 判断是否相同树的函数public boolean isSameTree(TreeNode p, TreeNode q) {// 如果左右子节点都为空,则相同if (p == null && q == null) {return true;}// 如果左右子节点其中一个为空,另一个不为空,则不相同if (p == null || q == null) {return false;}// 如果左右子节点的值不相等,则不相同if (p.val != q.val) {return false;}// 递归比较左子节点的左子树与右子节点的右子树,以及左子节点的右子树与右子节点的左子树是否相同boolean left = isSameTree(p.left, q.left);boolean right = isSameTree(p.right, q.right);// 如果左右子树都相同,则整体相同return left && right;}
}
104.二叉树的最大深度
104. 二叉树的最大深度
简单
给定一个二叉树 root
,返回其最大深度。
二叉树的 最大深度 是指从根节点到最远叶子节点的最长路径上的节点数。
示例 1:
输入:root = [3,9,20,null,null,15,7]
输出:3
示例 2:
输入:root = [1,null,2]
输出:2
提示:
- 树中节点的数量在
[0, 104]
区间内。 -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 int maxDepth(TreeNode root) {// 如果根节点为空,直接返回深度为0if (root == null) {return 0;}// 创建一个队列用于辅助层序遍历Queue<TreeNode> queue = new LinkedList<>();// 将根节点加入队列queue.offer(root);int depth = 0;// 当队列不为空时,继续遍历while (!queue.isEmpty()) {// 记录当前层的节点数int size = queue.size();// 遍历当前层的所有节点while (size-- > 0) {// 从队列中取出一个节点TreeNode node = queue.poll();// 将当前节点的左子节点加入队列(如果存在)if (node.left != null) {queue.offer(node.left);}// 将当前节点的右子节点加入队列(如果存在)if (node.right != null) {queue.offer(node.right);}}depth++; // 深度加1}// 返回树的最大深度return depth;}
}
深度优先遍历
求深度可看做是求高度,通过递归的方式,结束条件是节点为空,返回高度为0,每一个节点求出子树高度的最大值加一为该节点的高度,根节点的高度即为二叉树的最大深度
/*** 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) {// 如果根节点为空,树的深度为0if (root == null) {return 0;}// 分别计算左右子树的深度int leftHeight = maxDepth(root.left);int rightHeight = maxDepth(root.right);// 取左右子树深度的最大值,并加上根节点的深度1,得到整棵树的深度int height = Math.max(leftHeight, rightHeight) + 1;return height;}
}
559.N叉树的最大深度
559. N 叉树的最大深度
简单
给定一个 N 叉树,找到其最大深度。
最大深度是指从根节点到最远叶子节点的最长路径上的节点总数。
N 叉树输入按层序遍历序列化表示,每组子节点由空值分隔(请参见示例)。
示例 1:
输入:root = [1,null,3,2,4,null,5,6]
输出:3
示例 2:
输入:root = [1,null,2,3,4,5,null,null,6,7,null,8,null,9,10,null,null,11,null,12,null,13,null,null,14]
输出:5
提示:
- 树的深度不会超过
1000
。 - 树的节点数目位于
[0, 104]
之间。
深度优先遍历
/*
// 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 int maxDepth(Node root) {// 初始化最大深度为0int max = 0;// 如果根节点为空,返回0if (root == null) {return 0;}// 遍历子节点列表for (Node child : root.children) {// 递归计算子节点的最大深度,并更新最大值max = Math.max(max, maxDepth(child));}// 返回最大深度加上当前节点的深度1return max + 1;}
}
广度优先遍历
/*
// 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 int maxDepth(Node root) {// 如果根节点为空,直接返回深度为0if (root == null) {return 0;}// 创建一个队列用于辅助层序遍历Queue<Node> queue = new LinkedList<>();// 将根节点加入队列queue.offer(root);int depth = 0;// 当队列不为空时,继续遍历while (!queue.isEmpty()) {// 记录当前层的节点数int size = queue.size();// 遍历当前层的所有节点while (size-- > 0) {// 从队列中取出一个节点Node node = queue.poll();// 将当前节点的子节点加入队列if (!node.children.isEmpty()) {for (Node child : node.children) {queue.offer(child);}}}depth++; // 深度加1}// 返回树的最大深度return depth;}
}
111.二叉树的最小深度
111. 二叉树的最小深度
简单
给定一个二叉树,找出其最小深度。
最小深度是从根节点到最近叶子节点的最短路径上的节点数量。
说明:叶子节点是指没有子节点的节点。
示例 1:
输入:root = [3,9,20,null,null,15,7]
输出:2
示例 2:
输入:root = [2,null,3,null,4,null,5,null,6]
输出:5
提示:
- 树中节点数的范围在
[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) {// 如果根节点为空,直接返回深度为0if (root == null) {return 0;}// 创建一个队列用于辅助层序遍历Queue<TreeNode> queue = new LinkedList<>();// 将根节点加入队列queue.offer(root);int depth = 1;// 当队列不为空时,继续遍历while (!queue.isEmpty()) {// 记录当前层的节点数int size = queue.size();// 遍历当前层的所有节点while (size-- > 0) {// 从队列中取出一个节点TreeNode node = queue.poll();//如果当前节点的左右孩子都为空,直接返回最小深度if (node.left == null && node.right == null){return depth;}// 将当前节点的左子节点加入队列(如果存在)if (node.left != null) {queue.offer(node.left);}// 将当前节点的右子节点加入队列(如果存在)if (node.right != null) {queue.offer(node.right);}}depth++; // 深度加1}// 返回树的深度return depth;}
}
深度优先遍历
这里的深度优先遍历与求二叉树的最大深度有不同的地方,要着重明白最小深度是指叶节点到根节点的距离
采用和求二叉树最大深度的求法的话,会导致出现如下情况
故要对左子树为空或者右子树为空的情况单独判断
/*** 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) {// 如果根节点为空,返回深度为0if (root == null) {return 0;}// 计算左子树的最小深度int leftHeight = minDepth(root.left);// 计算右子树的最小深度int rightHeight = minDepth(root.right);// 如果左子树为空而右子树不为空,返回右子树的最小深度加上根节点深度if (root.left == null && root.right != null) {return rightHeight + 1;}// 如果右子树为空而左子树不为空,返回左子树的最小深度加上根节点深度if (root.left != null && root.right == null) {return leftHeight + 1;}// 返回左右子树最小深度的较小值加上根节点深度int result = Math.min(leftHeight, rightHeight) + 1;return result;}
}
222.完全二叉树的节点个数
222. 完全二叉树的节点个数
简单
给你一棵 完全二叉树 的根节点 root
,求出该树的节点个数。
完全二叉树 的定义如下:在完全二叉树中,除了最底层节点可能没填满外,其余每层节点数都达到最大值,并且最下面一层的节点都集中在该层最左边的若干位置。若最底层为第 h
层,则该层包含 1~ 2h
个节点。
示例 1:
输入:root = [1,2,3,4,5,6]
输出:6
示例 2:
输入:root = []
输出:0
示例 3:
输入:root = [1]
输出:1
提示:
- 树中节点的数目范围是
[0, 5 * 104]
0 <= Node.val <= 5 * 104
- 题目数据保证输入的树是 完全二叉树
进阶:遍历树来统计节点是一种时间复杂度为 O(n)
的简单解决方案。你可以设计一个更快的算法吗?
利用完全二叉树的性质。逐层找出完美二叉树,通过公式求出节点个数返回
/*** 二叉树节点的定义*/
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) {// 如果根节点为空,返回0if (root == null) {return 0;}// 初始化左子树和右子树的高度为0,并找到最左边和最右边的叶节点int leftHeight = 0;int rightHeight = 0;TreeNode turnLeft = root;while (turnLeft != null) {turnLeft = turnLeft.left;leftHeight++;}TreeNode turnRight = root;while (turnRight != null) {turnRight = turnRight.right;rightHeight++;}// 如果左右子树高度相等,说明是满二叉树,直接返回节点数if (leftHeight == rightHeight) {return (2 << (leftHeight - 1)) - 1; // 注意(2<<1) 相当于2^2,所以leftHeight要减一}// 如果左右子树高度不相等,分别计算左右子树的节点数int leftCount = countNodes(root.left);int rightCount = countNodes(root.right);// 返回左右子树节点数加上当前节点return leftCount + rightCount + 1;}
}
110.平衡二叉树
110. 平衡二叉树
简单
给定一个二叉树,判断它是否是高度平衡的二叉树。
本题中,一棵高度平衡二叉树定义为:
一个二叉树每个节点 的左右两个子树的高度差的绝对值不超过 1 。
示例 1:
输入:root = [3,9,20,null,null,15,7]
输出:true
示例 2:
输入:root = [1,2,2,3,3,null,null,4,4]
输出:false
示例 3:
输入:root = []
输出:true
提示:
- 树中的节点数在范围
[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;* }* }*/
class Solution {/*** 判断二叉树是否平衡*/public boolean isBalanced(TreeNode root) {// 如果平衡函数返回-1,说明不平衡if (balanced(root) == -1) {return false;}// 否则说明平衡return true;}/*** 计算二叉树的高度,如果不平衡则返回-1*/public int balanced(TreeNode root) {// 如果节点为空,高度为0if (root == null) {return 0;}// 计算左子树的高度int leftHeight = balanced(root.left);// 如果左子树不平衡,直接返回-1if (leftHeight == -1) {return -1;}// 计算右子树的高度int rightHeight = balanced(root.right);// 如果右子树不平衡,直接返回-1if (rightHeight == -1) {return -1;}// 如果左右子树高度差超过1,说明不平衡,返回-1if (Math.abs(leftHeight - rightHeight) > 1) {return -1;}// 返回左右子树中较大的高度加上当前节点的高度return Math.max(leftHeight, rightHeight) + 1;}
}
广度优先遍历
计算每个节点的高度,通过迭代遍历判断左右子树的高度差是否大于一
class Solution {/*** 迭代法,效率较低,计算高度时会重复遍历* 时间复杂度:O(n^2)*/public boolean isBalanced(TreeNode root) {if (root == null) {return true;}Stack<TreeNode> stack = new Stack<>();TreeNode pre = null;while (root!= null || !stack.isEmpty()) {while (root != null) {stack.push(root);root = root.left;}TreeNode inNode = stack.peek();// 右结点为null或已经遍历过if (inNode.right == null || inNode.right == pre) {// 比较左右子树的高度差,输出if (Math.abs(getHeight(inNode.left) - getHeight(inNode.right)) > 1) {return false;}stack.pop();pre = inNode;root = null;// 当前结点下,没有要遍历的结点了} else {root = inNode.right;// 右结点还没遍历,遍历右结点}}return true;}/*** 层序遍历,求结点的高度*/public int getHeight(TreeNode root) {if (root == null) {return 0;}Deque<TreeNode> deque = new LinkedList<>();deque.offer(root);int depth = 0;while (!deque.isEmpty()) {int size = deque.size();depth++;for (int i = 0; i < size; i++) {TreeNode poll = deque.poll();if (poll.left != null) {deque.offer(poll.left);}if (poll.right != null) {deque.offer(poll.right);}}}return depth;}
}
257.二叉树的所有路径
257. 二叉树的所有路径
简单
给你一个二叉树的根节点 root
,按 任意顺序 ,返回所有从根节点到叶子节点的路径。
叶子节点 是指没有子节点的节点。
示例 1:
输入:root = [1,2,3,null,5]
输出:["1->2->5","1->3"]
示例 2:
输入:root = [1]
输出:["1"]
提示:
- 树中节点的数目在范围
[1, 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<String> binaryTreePaths(TreeNode root) {List<String> result = new ArrayList<>();path(root, "", result);return result;}/*** 辅助函数,递归遍历二叉树并构建路径*/public void path(TreeNode root, String path, List<String> result) {// 如果节点为空,直接返回if (root == null) {return;}// 构建当前路径的字符串表示StringBuilder pathSB = new StringBuilder(path);pathSB.append(Integer.toString(root.val));// 如果当前节点是叶子节点,将路径加入结果列表if (root.left == null && root.right == null) {result.add(pathSB.toString());} else {// 否则,继续递归遍历左右子树pathSB.append("->"); // 添加箭头分隔符path(root.left, pathSB.toString(), result);path(root.right, pathSB.toString(), result);}}
}
层序遍历
通过一个栈,节点和路径同时入栈和出栈,同样到叶子节点的话将路径传入结果集合中
class Solution {/*** 迭代法*/public List<String> binaryTreePaths(TreeNode root) {List<String> result = new ArrayList<>();if (root == null)return result;Stack<Object> stack = new Stack<>();// 节点和路径同时入栈stack.push(root);stack.push(root.val + "");while (!stack.isEmpty()) {// 节点和路径同时出栈String path = (String) stack.pop();TreeNode node = (TreeNode) stack.pop();// 若找到叶子节点if (node.left == null && node.right == null) {result.add(path);}//右子节点不为空if (node.right != null) {stack.push(node.right);stack.push(path + "->" + node.right.val);}//左子节点不为空if (node.left != null) {stack.push(node.left);stack.push(path + "->" + node.left.val);}}return result;}
}