刷题日期:下午4:25 2021年5月18日星期二
个人刷题记录,代码收集,来源皆为leetcode
经过多方讨论和请教,现在打算往Java方向发力
主要答题语言为Java
题目:
剑指 Offer 55 - I. 二叉树的深度
难度简单118
输入一棵二叉树的根节点,求该树的深度。从根节点到叶节点依次经过的节点(含根、叶节点)形成树的一条路径,最长路径的长度为树的深度。
例如:
给定二叉树 [3,9,20,null,null,15,7]
,
3
/ \
9 20
/ \
15 7
返回它的最大深度 3 。
提示:
节点总数 <= 10000
题目分析
至少也得一次遍历,然后遍历时定义一个全局变量,每下一层就加1,定义一个最大值不断比较。
初始解答:
/**
* Definition for a binary tree node.
* public class TreeNode {
* int val;
* TreeNode left;
* TreeNode right;
* TreeNode(int x) { val = x; }
* }
*/
class Solution {
int count = 1, res = 1; //当前深度和最大深度
public int maxDepth(TreeNode root) {
if(root == null) {
return 0;
}
dfs(root);
return res;
}
private void dfs(TreeNode root) {
if(root == null) {
count = 1;
return;
} else {
count ++;
if(root.left != null && root.right != null) {
dfs(root.left);
}
if(root.left != null && root.right == null) {
// count ++;
dfs(root.left);
}
if(root.left == null && root.right != null) {
// count ++;
dfs(root.right);
}
if(root.left == null && root.right == null) return;
}
res = Math.max(count, res);
return;
}
}
我也不知道怎么就能把两个元素的算出来三层
添加备注 输入: [1,2]
输出: 3
预期结果: 2
/**
* Definition for a binary tree node.
* public class TreeNode {
* int val;
* TreeNode left;
* TreeNode right;
* TreeNode(int x) { val = x; }
* }
*/
class Solution {
public int maxDepth(TreeNode root) {
return root == null ? 0 : Math.max(maxDepth(root.left), maxDepth(root.right)) + 1;
}
}
自叹不如,哎。 执行结果:通过
显示详情 添加备注
执行用时:0 ms, 在所有 Java 提交中击败了100.00%的用户
内存消耗:38.1 MB, 在所有 Java 提交中击败了94.61%的用户
层序遍历:
/**
* Definition for a binary tree node.
* public class TreeNode {
* int val;
* TreeNode left;
* TreeNode right;
* TreeNode(int x) { val = x; }
* }
*/
class Solution {
public int maxDepth(TreeNode root) {
if(root == null) return 0;
//定义存放树节点的链表,后面没看懂
List<TreeNode> queue = new LinkedList<>() {{ add(root);}}, tmp;
int res = 0; //计数器
while(!queue.isEmpty()) {
//队列非空
tmp = new LinkedList<>(); //临时队
for(TreeNode node : queue) {
//原来都可以这么遍历
if(node.left != null) tmp.add(node.left); //只要有就加
if(node.right != null) tmp.add(node.right);
}
queue = tmp; //下一层
res++; //计数器自增
}
return res;
}
}
执行结果: 通过
显示详情 添加备注
执行用时:2 ms, 在所有 Java 提交中击败了10.13%的用户
内存消耗:38.1 MB, 在所有 Java 提交中击败了94.97%的用户
学习他人:
方法一:
mata川L5 (编辑过)2020-02-13 递归,java一行解决
class Solution {
public int maxDepth(TreeNode root) {
return root == null ? 0 : Math.max(maxDepth(root.left), maxDepth(root.right)) + 1;
}
}
方法二:
jackelyjL1 2020-03-03
这种题如果面试时出,多半会要求你用非递归写法
class Solution {
public int maxDepth(TreeNode root) {
if (root == null) {
return 0;
}
Stack<Pair<TreeNode, Integer>> stack = new Stack<>();
stack.add(new Pair<>(root, 1));
int h = 0;
while (!stack.isEmpty()) {
Pair<TreeNode, Integer> pair = stack.pop();
h = Math.max(pair.getValue(), h);
if (pair.getKey().right != null) {
stack.push(new Pair<>(pair.getKey().right, pair.getValue() + 1));
}
if (pair.getKey().left != null) {
stack.push(new Pair<>(pair.getKey().left, pair.getValue() + 1));
}
}
return h;
}
}
方法三:
Aurora 2020-05-12 java
//递归
class Solution {
public int maxDepth(TreeNode root) {
if(root == null) return 0;
int nLeft = maxDepth(root.left);
int nRight = maxDepth(root.right);
return nLeft > nRight ? nLeft + 1 : nRight + 1;
}
}
//层次遍历
class Solution {
public int maxDepth(TreeNode root) {
if(root == null) return 0;
Queue<TreeNode> queue = new LinkedList<>(){{add(root);}};
int depth = 0;
while(!queue.isEmpty()){
int cursize = queue.size();
for(int i = 0; i < cursize; i++){
TreeNode temp = queue.poll();
if(temp.left != null) queue.add(temp.left);
if(temp.right != null) queue.add(temp.right);
}
depth++;
}
return depth;
}
}
方法四:
K神 树的遍历方式总体分为两类:深度优先搜索(DFS)、广度优先搜索(BFS);
常见的 DFS : 先序遍历、中序遍历、后序遍历;
常见的 BFS : 层序遍历(即按层遍历)。
- 求树的深度需要遍历树的所有节点,本文将介绍基于 后序遍历(DFS) 和 层序遍历(BFS) 的两种解法。
作者:jyd
链接:https://leetcode-cn.com/problems/er-cha-shu-de-shen-du-lcof/solution/mian-shi-ti-55-i-er-cha-shu-de-shen-du-xian-xu-bia/
来源:力扣(LeetCode)
后序遍历(DFS)
- 树的后序遍历 / 深度优先搜索往往利用 递归 或 栈 实现,本文使用递归实现。
- 关键点: 此树的深度和其左(右)子树的深度之间的关系。显然,此树的深度 等于 左子树的深度 与 右子树的深度 中的 最大值 +1 。
class Solution {
public int maxDepth(TreeNode root) {
if(root == null) return 0;
return Math.max(maxDepth(root.left), maxDepth(root.right)) + 1;
}
}
层序遍历(BFS)
- 树的层序遍历 / 广度优先搜索往往利用 队列 实现。
- 关键点: 每遍历一层,则计数器 +1 ,直到遍历完成,则可得到树的深度。
class Solution {
public int maxDepth(TreeNode root) {
if(root == null) return 0;
List<TreeNode> queue = new LinkedList<>() {{ add(root); }}, tmp;
int res = 0;
while(!queue.isEmpty()) {
tmp = new LinkedList<>();
for(TreeNode node : queue) {
if(node.left != null) tmp.add(node.left);
if(node.right != null) tmp.add(node.right);
}
queue = tmp;
res++;
}
return res;
}
}
题目:
剑指 Offer 55 - II. 平衡二叉树
难度简单149
输入一棵二叉树的根节点,判断该树是不是平衡二叉树。如果某二叉树中任意节点的左右子树的深度相差不超过1,那么它就是一棵平衡二叉树。
示例 1:
给定二叉树 [3,9,20,null,null,15,7]
3
/ \
9 20
/ \
15 7
返回 true
。
示例 2:
给定二叉树 [1,2,2,3,3,null,null,4,4]
1
/ \
2 2
/ \
3 3
/ \
4 4
返回 false
。
限制:
0 <= 树的结点个数 <= 10000
题目分析
基于上一题的话,就是不断判断左右子树的深度,然后比较res是否>1。
初始解答:
class Solution {
public boolean isBalanced(TreeNode root) {
if(root == null) return false;
if((maxDepth(root.left) - maxDepth(root.right)) > 1) return false;
else return true;
return isBalanced(root.left) && isBalanced(root.right);
}
private int maxDepth(TreeNode root) {
if(root == null) return 0;
return Math.max(maxDepth(root.left), maxDepth(root.right)) + 1;
}
}
Line 10: error: unreachable statement return true && isBalanced(root.left) && isBalanced(root.right);
没懂错在写法上了吗,返回的不就是布尔型变量么。
参考方法一改给判断加上了绝对值,去掉了else,然后就好了。
class Solution {
public boolean isBalanced(TreeNode root) {
if(root == null) return true;
if(Math.abs(maxDepth(root.left) - maxDepth(root.right)) > 1) return false;
return isBalanced(root.left) && isBalanced(root.right);
}
private int maxDepth(TreeNode root) {
if(root == null) return 0;
return Math.max(maxDepth(root.left), maxDepth(root.right)) + 1;
}
}
执行结果:通过
显示详情 添加备注
执行用时:1 ms, 在所有 Java 提交中击败了100.00%的用户
内存消耗:38.3 MB, 在所有 Java 提交中击败了89.67%的用户
究极一行写法:
class Solution {
public boolean isBalanced(TreeNode root) {
return root == null ? true : Math.abs(maxDepth(root.left) - maxDepth(root.right)) <= 1 && isBalanced(root.left) && isBalanced(root.right);
}
private int maxDepth(TreeNode root) {
return root == null ? 0 : Math.max(maxDepth(root.left), maxDepth(root.right)) + 1;
}
}
执行结果:通过
显示详情 添加备注
执行用时:1 ms, 在所有 Java 提交中击败了100.00%的用户
内存消耗:38.5 MB, 在所有 Java 提交中击败了58.68%的用户
学习他人:
方法一:
2020-02-17
class Solution {
public boolean isBalanced(TreeNode root) {
if(root==null) return true;
if(Math.abs(getHigh(root.left)-getHigh(root.right))<=1){
return isBalanced(root.left)&&isBalanced(root.right);
}
return false;
}
private int getHigh(TreeNode root){
if(root==null) return 0;
return Math.max(getHigh(root.left),getHigh(root.right))+1;
}
}
方法二:
RaymondL1 1 小时前
class Solution {
public boolean isBalanced(TreeNode root) {
if(travel(root)>=0){
return true;
}
return false;
}
public int travel(TreeNode root){
if(root==null){return 0;}
int left = travel(root.left)+1;
int right = travel(root.right)+1;
if(Math.abs(left-right)<=1){
return Math.max(left, right);
}
return -100;
}
}
方法三:
唐東L1 2021-04-05
我做出来第第一道递归题,纪念一下,果然刷题出奇迹,昨天还云里雾里,今天就优点眉目了。哈哈哈哈
class Solution {
public boolean isBalanced(TreeNode root) {
//需要左右树的高度和是否平衡树
if(root == null) return true;
int leftD = depth(root.left);
int rightD = depth(root.right); //左右子树深度
return isBalanced(root.left) && isBalanced(root.right) && Math.abs(leftD - rightD) < 2;
}
public int depth(TreeNode zroot){
if (zroot == null)
return 0;
int left_depth = depth(zroot.left); //递归
int right_depth = depth(zroot.right);
return Math.max(left_depth, right_depth) + 1;
}
}
方法四:
苏幕遮L2 2021-04-30 年轻人用数组来引用 来剪枝 来偷袭
public boolean isBalanced(TreeNode root) {
boolean res[] = new boolean[]{true};
deep(root, res);
return res[0];
}
public int deep(TreeNode root, boolean res[]) {
if (root == null || res[0] == false) {
return 0;
}
int dl = deep(root.left, res);
int dr = deep(root.right, res);
if (Math.abs(dl - dr) > 1) {
res[0] = false;
return 0;
} else {
return Math.max(dl, dr) + 1;
}
}
方法五:
K神 以下两种方法均基于以下性质推出: 此树的深度 等于 左子树的深度 与 右子树的深度 中的 最大值 +1 。
后序遍历 + 剪枝 (从底至顶)
此方法为本题的最优解法,但剪枝的方法不易第一时间想到。
思路是对二叉树做后序遍历,从底至顶返回子树深度,若判定某子树不是平衡树则 “剪枝” ,直接向上返回。
作者:jyd
链接:https://leetcode-cn.com/problems/ping-heng-er-cha-shu-lcof/solution/mian-shi-ti-55-ii-ping-heng-er-cha-shu-cong-di-zhi/
来源:力扣(LeetCode)
class Solution {
public boolean isBalanced(TreeNode root) {
return recur(root) != -1;
}
private int recur(TreeNode root) {
if (root == null) return 0;
int left = recur(root.left);
if(left == -1) return -1;
int right = recur(root.right);
if(right == -1) return -1;
return Math.abs(left - right) < 2 ? Math.max(left, right) + 1 : -1;
}
}
莫非L3 (编辑过)2020-06-16
感谢分享,这里对第一种方法的Java代码根据个人理解加了一些注释,应该更容易理解:
public class Solution55_2 {
public boolean isBalanced(TreeNode root) {
return dfs(root)==-1?false:true;
}
//用left,right记录root左右子节点的深度,避免遍历root时对左右节点的深度进行重复计算。
//考虑到需要同时记录各个节点的深度和其是否符合平衡性要求,这里的返回值设为int,用一个特殊值-1来表示出现不平衡的节点的情况,而不是一般采用的boolean
public int dfs(TreeNode root){
//用后序遍历的方式遍历二叉树的每个节点(从底至顶),先左子树,再右子树,最后根节点,
if(root==null) return 0;//root等于0时,该节点符合要求,返回其深度0,而不返回-1;
int left = dfs(root.left);//left最开始的取值为0,从底朝上遍历,先左子树,后右子树,最后根节点
if(left==-1) return -1;//若出现节点的深度为-1,则进行剪枝,开始向上返回,之后的迭代不再进行
int right = dfs(root.right);
if(right==-1) return -1;
return Math.abs(right-left)<2?Math.max(left,right)+1:-1;//+1不能少
//最开始计算的是左子树最左侧的一个叶节点,其左右子节点不存在,left=0,right=0,满足条件,返回该叶节点的深度max(0,0)+1=1;
}
}
如有不对还请指正,谢谢。
先序遍历 + 判断深度 (从顶至底)
此方法容易想到,但会产生大量重复计算,时间复杂度较高。
思路是构造一个获取当前子树的深度的函数 depth(root) (即 面试题55 - I. 二叉树的深度 ),通过比较某子树的左右子树的深度差 abs(depth(root.left) - depth(root.right)) <= 1 是否成立,来判断某子树是否是二叉平衡树。若所有子树都平衡,则此树平衡。
class Solution {
public boolean isBalanced(TreeNode root) {
if (root == null) return true;
return Math.abs(depth(root.left) - depth(root.right)) <= 1 && isBalanced(root.left) && isBalanced(root.right);
}
private int depth(TreeNode root) {
if (root == null) return 0;
return Math.max(depth(root.left), depth(root.right)) + 1;
}
}
总结
以上就是本题的内容和学习过程了,二叉树的遍历也是面试中常见的考点,还是要掌握的。
欢迎讨论,共同进步。