【二叉树】算法例题

news2024/11/30 10:53:11

目录

 九、二叉树

68. 二叉树的最大深度 ① ×

69. 相同的树 ① √

70. 翻转二叉树 ① ×

71. 对称二叉树 ① ×

72. 从前序与中序遍历序列构造二叉树 ② ×

73. 从中序与后续遍历序列构造二叉树 ②

74. 填充每个节点的下一个右侧节点指针 II ② ×

75. 二叉树展开为链表 ② ×

76. 路径总和 ① ×

77. 求根节点到叶节点数字之和 ② ×

78. 二叉树中的最大路径和 ③

79. 二叉搜索树迭代器 ②

80. 完全二叉树的节点个数 ① √-

81. 二叉树的最近公共祖先 ②

十、二叉树层次遍历

82. 二叉树的右视图 ② ×

83. 二叉树的层平均值 ① √-

84. 二叉树的层序遍历 ② √

85. 二叉树的锯齿形层序遍历 ② √

十一、二叉搜索树

86. 二叉搜索树的最小绝对差 ①

87. 二叉搜索树中第K小的元素 ②

88. 验证二叉搜索树 ②


 九、二叉树

68. 二叉树的最大深度 ① ×

给定一个二叉树 root ,返回其最大深度。

二叉树的 最大深度 是指从根节点到最远叶子节点的最长路径上的节点数。

示例 1:

输入:root = [3,9,20,null,null,15,7]
输出:3

示例 2:

输入:root = [1,null,2]
输出:2

提示:

  • 树中节点的数量在 [0, 104] 区间内。
  • -100 <= Node.val <= 100

思路分析:力扣(LeetCode)官网 - 全球极客挚爱的技术成长平台

方法2:(0ms)

    public int maxDepth(TreeNode root) {
        if (root == null) return 0;
        return Math.max(maxDepth(root.left), maxDepth(root.right)) + 1;
    }

作者:Krahets
链接:https://leetcode.cn/problems/maximum-depth-of-binary-tree/solutions/2361697/104-er-cha-shu-de-zui-da-shen-du-hou-xu-txzrx/

69. 相同的树 ① √

给你两棵二叉树的根节点 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

方法1:(0ms)

    public boolean isSameTree(TreeNode p, TreeNode q) {
        if (p == null && q != null) {
            return false;
        } else if (p != null && q == null) {
            return false;
        } else if (p == null && q == null) {
            return true;
        } else if (p != null && q != null && p.val == q.val) {
            if (isSameTree(p.left, q.left) && isSameTree(p.right, q.right)) {
                return true;
            } else {
                return false;
            }
        } else if (p != null && q != null && p.val != q.val) {
            return false;
        } else {
            return false;
        }
    }

方法2:力扣(LeetCode)官网 - 全球极客挚爱的技术成长平台

    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;
        return isSameTree(p.left, q.left) && isSameTree(p.right, q.right);
    }

作者:画手大鹏
链接:https://leetcode.cn/problems/same-tree/solutions/12686/hua-jie-suan-fa-100-xiang-tong-de-shu-by-guanpengc/

70. 翻转二叉树 ① ×

给你一棵二叉树的根节点 root ,翻转这棵二叉树,并返回其根节点。

示例 1:

输入:root = [4,2,7,1,3,6,9]
输出:[4,7,2,9,6,3,1]

示例 2:

示例 3:

输入:root = []
输出:[]

提示:

  • 树中节点数目范围在 [0, 100] 内
  • -100 <= Node.val <= 100

解析:力扣(LeetCode)官网 - 全球极客挚爱的技术成长平台

方法2:(0ms)

     public TreeNode invertTree(TreeNode root) {
        //递归函数的终止条件,节点为空时返回
		if(root==null) {
			return null;
		}
		//下面三句是将当前节点的左右子树交换
		TreeNode tmp = root.right;
		root.right = root.left;
		root.left = tmp;
		//递归交换当前节点的 左子树
		invertTree(root.left);
		//递归交换当前节点的 右子树
		invertTree(root.right);
		//函数返回时就表示当前这个节点,以及它的左右子树
		//都已经交换完了
		return root;
    }

作者:王尼玛
链接:https://leetcode.cn/problems/invert-binary-tree/solutions/73159/dong-hua-yan-shi-liang-chong-shi-xian-226-fan-zhua/

方法3:(0ms)

     public TreeNode invertTree(TreeNode root) {
		if(root==null) {
			return null;
		}
		//将二叉树中的节点逐层放入队列中,再迭代处理队列中的元素
		LinkedList<TreeNode> queue = new LinkedList<TreeNode>();
		queue.add(root);
		while(!queue.isEmpty()) {
			//每次都从队列中拿一个节点,并交换这个节点的左右子树
			TreeNode tmp = queue.poll();
			TreeNode left = tmp.left;
			tmp.left = tmp.right;
			tmp.right = left;
			//如果当前节点的左子树不为空,则放入队列等待后续处理
			if(tmp.left!=null) {
				queue.add(tmp.left);
			}
			//如果当前节点的右子树不为空,则放入队列等待后续处理
			if(tmp.right!=null) {
				queue.add(tmp.right);
			}
			
		}
		//返回处理完的根节点
		return root;
    }

 方法4:(0ms)

    public TreeNode invertTree(TreeNode root) {
        if (root == null)
            return root;
        TreeNode temp = root.left;
        root.left = invertTree(root.right);
        root.right = invertTree(temp);
        return root;
    }

71. 对称二叉树 ① ×

给你一个二叉树的根节点 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

进阶:你可以运用递归和迭代两种方法解决这个问题吗?

题解思路:. - 力扣(LeetCode)

方法2:(0ms)

	public boolean isSymmetric(TreeNode root) {
		if(root==null) {
			return true;
		}
		//调用递归函数,比较左节点,右节点
		return dfs(root.left,root.right);
	}
	
	boolean dfs(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;
		}
		//再递归的比较 左节点的左孩子 和 右节点的右孩子
		//以及比较  左节点的右孩子 和 右节点的左孩子
		return dfs(left.left,right.right) && dfs(left.right,right.left);
	}

作者:王尼玛
链接:https://leetcode.cn/problems/symmetric-tree/solutions/46560/dong-hua-yan-shi-101-dui-cheng-er-cha-shu-by-user7/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

方法3:

	public boolean isSymmetric(TreeNode root) {
		if(root==null || (root.left==null && root.right==null)) {
			return true;
		}
		//用队列保存节点
		LinkedList<TreeNode> queue = new LinkedList<TreeNode>();
		//将根节点的左右孩子放到队列中
		queue.add(root.left);
		queue.add(root.right);
		while(queue.size()>0) {
			//从队列中取出两个节点,再比较这两个节点
			TreeNode left = queue.removeFirst();
			TreeNode right = queue.removeFirst();
			//如果两个节点都为空就继续循环,两者有一个为空就返回false
			if(left==null && right==null) {
				continue;
			}
			if(left==null || right==null) {
				return false;
			}
			if(left.val!=right.val) {
				return false;
			}
			//将左节点的左孩子, 右节点的右孩子放入队列
			queue.add(left.left);
			queue.add(right.right);
			//将左节点的右孩子,右节点的左孩子放入队列
			queue.add(left.right);
			queue.add(right.left);
		}
		
		return true;
	}

作者:王尼玛
链接:https://leetcode.cn/problems/symmetric-tree/solutions/46560/dong-hua-yan-shi-101-dui-cheng-er-cha-shu-by-user7/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

72. 从前序与中序遍历序列构造二叉树 ② ×

给定两个整数数组 preorder 和 inorder ,其中 preorder 是二叉树的先序遍历, inorder 是同一棵树的中序遍历,请构造二叉树并返回其根节点。

示例 1:

输入: preorder = [3,9,20,15,7], inorder = [9,3,15,20,7]
输出: [3,9,20,null,null,15,7]

示例 2:

输入: preorder = [-1], inorder = [-1]
输出: [-1]

提示:

  • 1 <= preorder.length <= 3000
  • inorder.length == preorder.length
  • -3000 <= preorder[i], inorder[i] <= 3000
  • preorder 和 inorder 均 无重复 元素
  • inorder 均出现在 preorder
  • preorder 保证 为二叉树的前序遍历序列
  • inorder 保证 为二叉树的中序遍历序列

题解:. - 力扣(LeetCode)

方法2:(1ms)  . - 力扣(LeetCode)

    int[] preorder;
    HashMap<Integer, Integer> dic = new HashMap<>();
    public TreeNode buildTree(int[] preorder, int[] inorder) {
        this.preorder = preorder;
        for(int i = 0; i < inorder.length; i++)
            dic.put(inorder[i], i);
        return recur(0, 0, inorder.length - 1);
    }
    TreeNode recur(int root, int left, int right) {
        if (left > right) return null;                          // 递归终止
        TreeNode node = new TreeNode(preorder[root]);          // 建立根节点
        int i = dic.get(preorder[root]);                       // 划分根节点、左子树、右子树
        node.left = recur(root + 1, left, i - 1);              // 开启左子树递归
        node.right = recur(root + i - left + 1, i + 1, right); // 开启右子树递归
        return node;                                           // 回溯返回根节点
    }

作者:Krahets
链接:https://leetcode.cn/problems/construct-binary-tree-from-preorder-and-inorder-traversal/solutions/2361558/105-cong-qian-xu-yu-zhong-xu-bian-li-xu-4lvkz/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

方法3:(1ms) 递归

. - 力扣(LeetCode)

    private Map<Integer, Integer> indexMap;

    public TreeNode myBuildTree(int[] preorder, int[] inorder, int preorder_left, int preorder_right, int inorder_left, int inorder_right) {
        if (preorder_left > preorder_right) {
            return null;
        }

        // 前序遍历中的第一个节点就是根节点
        int preorder_root = preorder_left;
        // 在中序遍历中定位根节点
        int inorder_root = indexMap.get(preorder[preorder_root]);
        
        // 先把根节点建立出来
        TreeNode root = new TreeNode(preorder[preorder_root]);
        // 得到左子树中的节点数目
        int size_left_subtree = inorder_root - inorder_left;
        // 递归地构造左子树,并连接到根节点
        // 先序遍历中「从 左边界+1 开始的 size_left_subtree」个元素就对应了中序遍历中「从 左边界 开始到 根节点定位-1」的元素
        root.left = myBuildTree(preorder, inorder, preorder_left + 1, preorder_left + size_left_subtree, inorder_left, inorder_root - 1);
        // 递归地构造右子树,并连接到根节点
        // 先序遍历中「从 左边界+1+左子树节点数目 开始到 右边界」的元素就对应了中序遍历中「从 根节点定位+1 到 右边界」的元素
        root.right = myBuildTree(preorder, inorder, preorder_left + size_left_subtree + 1, preorder_right, inorder_root + 1, inorder_right);
        return root;
    }

    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 myBuildTree(preorder, inorder, 0, n - 1, 0, n - 1);
    }

作者:力扣官方题解
链接:https://leetcode.cn/problems/construct-binary-tree-from-preorder-and-inorder-traversal/solutions/255811/cong-qian-xu-yu-zhong-xu-bian-li-xu-lie-gou-zao-9/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

方法4:(1ms) 迭代

    public TreeNode buildTree(int[] preorder, int[] inorder) {
        if (preorder == null || preorder.length == 0) {
            return null;
        }
        TreeNode root = new TreeNode(preorder[0]);
        Deque<TreeNode> stack = new LinkedList<TreeNode>();
        stack.push(root);
        int inorderIndex = 0;
        for (int i = 1; i < preorder.length; i++) {
            int preorderVal = preorder[i];
            TreeNode node = stack.peek();
            if (node.val != inorder[inorderIndex]) {
                node.left = new TreeNode(preorderVal);
                stack.push(node.left);
            } else {
                while (!stack.isEmpty() && stack.peek().val == inorder[inorderIndex]) {
                    node = stack.pop();
                    inorderIndex++;
                }
                node.right = new TreeNode(preorderVal);
                stack.push(node.right);
            }
        }
        return root;
    }

作者:力扣官方题解
链接:https://leetcode.cn/problems/construct-binary-tree-from-preorder-and-inorder-traversal/solutions/255811/cong-qian-xu-yu-zhong-xu-bian-li-xu-lie-gou-zao-9/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

73. 从中序与后续遍历序列构造二叉树 ②

74. 填充每个节点的下一个右侧节点指针 II ② ×

给定一个二叉树:

struct Node {
  int val;
  Node *left;
  Node *right;
  Node *next;
}

填充它的每个 next 指针,让这个指针指向其下一个右侧节点。如果找不到下一个右侧节点,则将 next 指针设置为 NULL 。

初始状态下,所有 next 指针都被设置为 NULL 。

示例 1:

输入:root = [1,2,3,4,5,null,7]
输出:[1,#,2,3,#,4,5,7,#]
解释:给定二叉树如图 A 所示,你的函数应该填充它的每个 next 指针,以指向其下一个右侧节点,如图 B 所示。序列化输出按层序遍历顺序(由 next 指针连接),'#' 表示每层的末尾。

示例 2:

输入:root = []
输出:[]

提示:

  • 树中的节点数在范围 [0, 6000] 内
  • -100 <= Node.val <= 100

进阶:

  • 你只能使用常量级额外空间。
  • 使用递归解题也符合要求,本题中递归程序的隐式栈空间不计入额外空间复杂度。

解题思路:. - 力扣(LeetCode)

方法2:(1ms)

    public Node connect(Node root) {
        if (root == null)
            return root;
        Queue<Node> queue = new LinkedList<>();
        queue.add(root);
        while (!queue.isEmpty()) {
            //每一层的数量
            int levelCount = queue.size();
            //前一个节点
            Node pre = null;
            for (int i = 0; i < levelCount; i++) {
                //出队
                Node node = queue.poll();
                //如果pre为空就表示node节点是这一行的第一个,
                //没有前一个节点指向他,否则就让前一个节点指向他
                if (pre != null) {
                    pre.next = node;
                }
                //然后再让当前节点成为前一个节点
                pre = node;
                //左右子节点如果不为空就入队
                if (node.left != null)
                    queue.add(node.left);
                if (node.right != null)
                    queue.add(node.right);
            }
        }
        return root;
    }

作者:数据结构和算法
链接:https://leetcode.cn/problems/populating-next-right-pointers-in-each-node-ii/solutions/429992/bfsjie-jue-zui-hao-de-ji-bai-liao-100de-yong-hu-by/

75. 二叉树展开为链表 ② ×

给你二叉树的根结点 root ,请你将它展开为一个单链表:

  • 展开后的单链表应该同样使用 TreeNode ,其中 right 子指针指向链表中下一个结点,而左子指针始终为 null 。
  • 展开后的单链表应该与二叉树 先序遍历 顺序相同。

示例 1:

输入:root = [1,2,5,3,4,null,6]
输出:[1,null,2,null,3,null,4,null,5,null,6]

示例 2:

输入:root = []
输出:[]

示例 3:

输入:root = [0]
输出:[0]

提示:

  • 树中结点数在范围 [0, 2000] 内
  • -100 <= Node.val <= 100

进阶:你可以使用原地算法(O(1) 额外空间)展开这棵树吗?

解题思路:. - 力扣(LeetCode)

方法2:(0ms)

public void flatten(TreeNode root) {
    while (root != null) { 
        //左子树为 null,直接考虑下一个节点
        if (root.left == null) {
            root = root.right;
        } else {
            // 找左子树最右边的节点
            TreeNode pre = root.left;
            while (pre.right != null) {
                pre = pre.right;
            } 
            //将原来的右子树接到左子树的最右边节点
            pre.right = root.right;
            // 将左子树插入到右子树的地方
            root.right = root.left;
            root.left = null;
            // 考虑下一个节点
            root = root.right;
        }
    }
}

作者:windliang
链接:https://leetcode.cn/problems/flatten-binary-tree-to-linked-list/solutions/17274/xiang-xi-tong-su-de-si-lu-fen-xi-duo-jie-fa-by--26/

76. 路径总和 ① ×

给你二叉树的根节点 root 和一个表示目标和的整数 targetSum 。判断该树中是否存在 根节点到叶子节点 的路径,这条路径上所有节点值相加等于目标和 targetSum 。如果存在,返回 true ;否则,返回 false 。

叶子节点 是指没有子节点的节点。

示例 1:

输入:root = [5,4,8,11,null,13,4,7,2,null,null,null,1], targetSum = 22
输出:true
解释:等于目标和的根节点到叶节点路径如上图所示。

示例 2:

输入:root = [1,2,3], targetSum = 5
输出:false
解释:树中存在两条根节点到叶子节点的路径:
(1 --> 2): 和为 3
(1 --> 3): 和为 4
不存在 sum = 5 的根节点到叶子节点的路径。

示例 3:

输入:root = [], targetSum = 0
输出:false
解释:由于树是空的,所以不存在根节点到叶子节点的路径。

提示:

  • 树中节点的数目在范围 [0, 5000] 内
  • -1000 <= Node.val <= 1000
  • -1000 <= targetSum <= 1000

解题思路:. - 力扣(LeetCode)

方法2:()

public boolean hasPathSum(TreeNode root, int sum) {
    // 如果根节点为空,直接返回false
    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);
}

方法2:(0ms)dfs

public boolean hasPathSum(TreeNode root, int sum) {
    // 如果根节点为空,直接返回false
    if (root == null) return false;
    // 调用深度优先搜索(DFS)函数,查找是否存在一条从根节点到叶子节点的路径,使得路径上的节点值之和等于给定的目标值
    return dfs(root, sum, root.val);
}

private boolean dfs(TreeNode root, int target, int pathSum) {
    // 如果当前节点为空,直接返回false
    if (root == null) return false;
    // 如果路径和等于目标值,并且当前节点是叶子节点(即左右子节点都为空),返回true
    if (pathSum == target && root.left == null && root.right == null) {
        return true;
    }
    // 初始化左右子树的标志位为false
    boolean leftFlag = false, rightFlag = false;
    // 如果左子节点不为空,递归地在左子树中查找路径,路径和等于当前路径和加上左子节点的值
    if (root.left != null) {
        leftFlag = dfs(root.left, target, pathSum + root.left.val);
    }
    // 如果右子节点不为空,递归地在右子树中查找路径,路径和等于当前路径和加上右子节点的值
    if (root.right != null) {
        rightFlag = dfs(root.right, target, pathSum + root.right.val);
    }
    // 如果左子树或右子树中存在满足条件的路径,返回true,否则返回false
    return leftFlag || rightFlag;
}

77. 求根节点到叶节点数字之和 ② ×

给你一个二叉树的根节点 root ,树中每个节点都存放有一个 0 到 9 之间的数字。

每条从根节点到叶节点的路径都代表一个数字:

  • 例如,从根节点到叶节点的路径 1 -> 2 -> 3 表示数字 123 。

计算从根节点到叶节点生成的 所有数字之和 。

叶节点 是指没有子节点的节点。

示例 1:

输入:root = [1,2,3]
输出:25
解释:
从根到叶子节点路径 1->2 代表数字 12 从根到叶子节点路径 1->3  代表数字 13 因此,数字总和 = 12 + 13 = 25

示例 2:

输入:root = [4,9,0,5,1]
输出:1026
解释:
从根到叶子节点路径 4->9->5 代表数字 495 从根到叶子节点路径 4->9->1 代表数字 491从根到叶子节点路径 4->0 代表数字 40 因此,数字总和 = 495 + 491 + 40 = 1026

提示:
  • 树中节点的数目在范围 [1, 1000] 内
  • 0 <= Node.val <= 9
  • 树的深度不超过 10

解题思路:. - 力扣(LeetCode)

方法2:(0ms)

    public int sumNumbers(TreeNode root) {
        return dfs(root, 0);
    }

    public int dfs(TreeNode root, int prevSum) {
        if (root == null) {
            return 0;
        }
        int sum = prevSum * 10 + root.val;
        if (root.left == null && root.right == null) {
            return sum;
        } else {
            return dfs(root.left, sum) + dfs(root.right, sum);
        }
    }

作者:力扣官方题解
链接:https://leetcode.cn/problems/sum-root-to-leaf-numbers/solutions/464666/qiu-gen-dao-xie-zi-jie-dian-shu-zi-zhi-he-by-leetc/

78. 二叉树中的最大路径和 ③

79. 二叉搜索树迭代器 ②

80. 完全二叉树的节点个数 ① √-

给你一棵 完全二叉树 的根节点 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) 的简单解决方案。你可以设计一个更快的算法吗?

力扣题解思路:

. - 力扣(LeetCode)

方法1:(7ms)

    public int countNodes(TreeNode root) {
        if (root == null){
            return 0;
        }
        Deque<TreeNode> deque = new ArrayDeque<>();
        deque.addLast(root);
        int count = 1;
        while (deque.size() > 0){
            TreeNode newRoot = deque.remove();
            TreeNode left = newRoot.left;
            TreeNode right = newRoot.right;
            if (left != null){
                deque.addLast(left);
                count++;
            }
            if (right != null){
                deque.addLast(right);
                count++;
            }
        }
        return count;
    }

fangfa 2:(0ms)

public int countNodes(TreeNode root) {
    if (root == null){
        return 0;
    }
    return countNodes(root.left) + countNodes(root.right) + 1;
}

作者:Wanglihao
链接:https://leetcode.cn/problems/count-complete-tree-nodes/solutions/21544/chang-gui-jie-fa-he-ji-bai-100de-javajie-fa-by-xia/

81. 二叉树的最近公共祖先 ②

十、二叉树层次遍历

82. 二叉树的右视图 ② ×

给定一个二叉树的 根节点 root,想象自己站在它的右侧,按照从顶部到底部的顺序,返回从右侧所能看到的节点值。

示例 1:

输入: [1,2,3,null,5,null,4]
输出: [1,3,4]

示例 2:

输入: [1,null,3]
输出: [1,3]

示例 3:

输入: []
输出: []

提示:

  • 二叉树的节点个数的范围是 [0,100]
  • -100 <= Node.val <= 100 

方法2:(0ms)  DFS

class Solution {
    List<Integer> res = new ArrayList<>();

    public List<Integer> rightSideView(TreeNode root) {
        dfs(root, 0); // 从根节点开始访问,根节点深度是0
        return res;
    }

    private void dfs(TreeNode root, int depth) {
        if (root == null) {
            return;
        }
        // 先访问 当前节点,再递归地访问 右子树 和 左子树。
        if (depth == res.size()) {   // 如果当前节点所在深度还没有出现在res里,说明在该深度下当前节点是第一个被访问的节点,因此将当前节点加入res中。
            res.add(root.val);
        }
        depth++;
        dfs(root.right, depth);
        dfs(root.left, depth);
    }
}

作者:Sweetiee 🍬
链接:https://leetcode.cn/problems/binary-tree-right-side-view/solutions/214871/jian-dan-bfsdfs-bi-xu-miao-dong-by-sweetiee/

方法3:(1ms)  BFS

class Solution {
    public List<Integer> rightSideView(TreeNode root) {
        List<Integer> res = new ArrayList<>();
        if (root == null) {
            return res;
        }
        Queue<TreeNode> queue = new LinkedList<>();
        queue.offer(root);
        while (!queue.isEmpty()) {
            int size = queue.size();
            for (int i = 0; i < size; i++) {
                TreeNode node = queue.poll();
                if (node.left != null) {
                    queue.offer(node.left);
                }
                if (node.right != null) {
                    queue.offer(node.right);
                }
                if (i == size - 1) {  //将当前层的最后一个节点放入结果列表
                    res.add(node.val);
                }
            }
        }
        return res;
    }
}

83. 二叉树的层平均值 ① √-

给定一个非空二叉树的根节点 root , 以数组的形式返回每一层节点的平均值。与实际答案相差 10-5 以内的答案可以被接受。

示例 1:

输入:root = [3,9,20,null,null,15,7]
输出:[3.00000,14.50000,11.00000]
解释:第 0 层的平均值为 3,第 1 层的平均值为 14.5,第 2 层的平均值为 11 。
因此返回 [3, 14.5, 11] 。

示例 2:

输入:root = [3,9,20,15,7]
输出:[3.00000,14.50000,11.00000]

提示:

  • 树中节点数量在 [1, 104] 范围内
  • -231 <= Node.val <= 231 - 1

题解:. - 力扣(LeetCode)

方法1:(2ms)

    public static List<Double> averageOfLevels(TreeNode root) {
        ArrayList<Double> list = new ArrayList<>();
        if (root == null){
            return list;
        }
        ArrayDeque<TreeNode> deque = new ArrayDeque<>();
        deque.addLast(root);
        list.add(new Double(root.val));
        while (deque.size() > 0){
            int size = deque.size();
            double sum = 0;
            int cnt = 0;

            for (int i = 0; i < size; i++) {
                TreeNode parent = deque.removeFirst();
                TreeNode left = parent.left;
                if (left != null){
                    deque.addLast(left);
                    sum += left.val;
                    cnt++;
                }

                TreeNode right = parent.right;
                if (right != null){
                    deque.addLast(right);
                    sum += right.val;
                    cnt++;
                }

            }
            if (cnt != 0) {
                list.add(sum / cnt);
            }
        }
        return list;
    }

84. 二叉树的层序遍历 ② √

给你二叉树的根节点 root ,返回其节点值的 层序遍历 。 (即逐层地,从左到右访问所有节点)。

示例 1:

输入:root = [3,9,20,null,null,15,7]
输出:[[3],[9,20],[15,7]]

示例 2:

输入:root = [1]
输出:[[1]]

示例 3:

输入:root = []
输出:[]

解题思路:. - 力扣(LeetCode)

提示:

  • 树中节点数目在范围 [0, 2000] 内
  • -1000 <= Node.val <= 1000

方法1:(1ms)

    public static List<List<Integer>> levelOrder(TreeNode root) {
        ArrayList<List<Integer>> list = new ArrayList<>();
        if (root == null){
            return list;
        }
        ArrayDeque<TreeNode> deque = new ArrayDeque<>();
        deque.addLast(root);
        int count = 0;
        ArrayList<Integer> subList = new ArrayList<>();
        subList.add(root.val);
        list.add(subList);
        while (deque.size() > 0){

            List<Integer> list1 = list.get(count);
            int size = list1.size();
            ArrayList<Integer> list2 = new ArrayList<>();
            for (int i = 0; i < size; i++) {
                TreeNode parent = deque.removeFirst();
                TreeNode left = parent.left;
                if (left != null){
                    deque.addLast(left);
                    list2.add(left.val);
                }
                TreeNode right = parent.right;
                if (right != null){
                    deque.addLast(right);
                    list2.add(right.val);
                }
            }
            if (list2.size() > 0) {
                list.add(list2);
            }
            count++;
        }
        return list;
    }

85. 二叉树的锯齿形层序遍历 ② √

给你二叉树的根节点 root ,返回其节点值的 锯齿形层序遍历 。(即先从左往右,再从右往左进行下一层遍历,以此类推,层与层之间交替进行)。

示例 1:

输入:root = [3,9,20,null,null,15,7]
输出:[[3],[20,9],[15,7]]

示例 2:

输入:root = [1]
输出:[[1]]

示例 3:

输入:root = []
输出:[]

提示:

  • 树中节点数目在范围 [0, 2000] 内
  • -100 <= Node.val <= 100

解题思路:. - 力扣(LeetCode)

方法1:(0ms)

    public static List<List<Integer>> zigzagLevelOrder(TreeNode root) {
        ArrayList<List<Integer>> result = new ArrayList<>();
        ArrayList<Integer> subList = new ArrayList<>();
        if (root == null){
            return result;
        }
        int count = 1;
        subList.add(root.val);
        result.add(subList);
        ArrayList<TreeNode> nodeList = new ArrayList<>();
        nodeList.add(root);
        ArrayDeque<List<TreeNode>> deque = new ArrayDeque<>();
        deque.addLast(nodeList);
        while (true){
            List<TreeNode> list = deque.remove();
            ArrayList<TreeNode> newNodeList = new ArrayList<>();
            ArrayList<Integer> newSubList = new ArrayList<>();
            int size = list.size();
            for (int i = 0; i < size; i++) {
                TreeNode tailNode = list.get(size - i - 1);
                TreeNode right = tailNode.right;
                TreeNode left = tailNode.left;
                if (count == 1){
                    if (right != null){
                        newNodeList.add(right);
                        newSubList.add(right.val);
                    }
                    if (left != null){
                        newNodeList.add(left);
                        newSubList.add(left.val);
                    }
                }else {
                    if (left != null){
                        newNodeList.add(left);
                        newSubList.add(left.val);
                    }
                    if (right != null){
                        newNodeList.add(right);
                        newSubList.add(right.val);
                    }
                }
            }

            count *= -1;
            if (newNodeList.size() == 0){
                break;
            }else {
                result.add(newSubList);
                deque.addLast(newNodeList);
            }
        }
        return result;
    }

十一、二叉搜索树

86. 二叉搜索树的最小绝对差 ①

87. 二叉搜索树中第K小的元素 ②

88. 验证二叉搜索树 ②

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1529518.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

鸿蒙实战开发:【FaultLoggerd组件】讲解

简介 Faultloggerd部件是OpenHarmony中C/C运行时崩溃临时日志的生成及管理模块。面向基于 Rust 开发的部件&#xff0c;Faultloggerd 提供了Rust Panic故障日志生成能力。系统开发者可以在预设的路径下找到故障日志&#xff0c;定位相关问题。 架构 Native InnerKits 接口 Si…

Marin说PCB之电源完整性之直流压降仿真CST--03

本期内容主要讲解的是关于在CST软件上电源直流压降仿真VRM的一些相关参数设置&#xff0c;小编我在之前文章中有说到过如何利用CST仿真电源信号的直流压降&#xff0c;不过有一些问题我这边再去补充一些。 首先就是VRM芯片的设置了&#xff0c;小编我还是按照之前那样设置&…

腾讯云k8s容器服务

1、新建一个集群 这个网址&#xff1a; 登录登录 - 腾讯云 2、选择第一个 3、名字随便起一个&#xff0c;然后基本默认就行 4、 组件配置直接跳过&#xff0c;信息确认&#xff0c;等待集群初始化&#xff0c;等10分钟左右&#xff08;容器服务需要充点钱才行&#xff09; 5…

学习vue3第八节(自定义指令 directive)

1、自定义指令的作用&#xff1a; 自定义指令是用来操作底层DOM的&#xff0c;尽管vue推崇数据驱动视图的理念&#xff0c;但并非所有情况都适合数据驱动。自定义指令就是一种有效的补充和拓展&#xff0c;不仅仅可用于定义任何DOM操作&#xff0c;并且是可以重复使用。 自定义…

杨氏矩阵的查找(复杂度<O(N))

题目&#xff1a; 解释&#xff1a;时间复杂度小于O(N)即不要一个一个的去遍历查找。 思路&#xff1a; 一个33的二维数组如图所示&#xff1a; 一&#xff1a;先找到一个最关键的数字&#xff0c;3&#xff08;下标为0,2&#xff09; 关键数的关键之处在于&#xff08;处于…

过拟合欠拟合

问题&#xff1a;训练数据训练的很好啊&#xff0c;误差也不大&#xff0c;为什么在测试集上面有问题呢&#xff1f; 当算法在某个数据集当中出现这种情况&#xff0c;可能就出现了过拟合现象。 1、 什么是过拟合与欠拟合 欠拟合 过拟合 分析第一种情况&#xff1a;因为机器…

[Python人工智能] 四十三.命名实体识别 (4)利用bert4keras构建Bert+BiLSTM-CRF实体识别模型

从本专栏开始,作者正式研究Python深度学习、神经网络及人工智能相关知识。前文讲解如何实现中文命名实体识别研究,构建BiGRU-CRF模型实现。这篇文章将继续以中文语料为主,介绍融合Bert的实体识别研究,使用bert4keras和kears包来构建Bert+BiLSTM-CRF模型。然而,该代码最终结…

Linux用户、用户组

用户管理命令&#xff1a; 首先要先知道两个配置文件&#xff1a;/etc/group 用户组配置文件/etc/passwd 保存了所有用户的用于读取的必要信息**/etc/shadow **是 Linux 系统中用于存储用户密码信息的文件。这个文件也被称为“影子文件”&#xff0c;因为它包含了 /etc/passwd…

Unity发布webgl设置占满浏览器运行

Unity发布webgl设置占满浏览器运行 Unity发布webgl的时候index.html的模板文件 模板文件路径&#xff0c;根据自己的需求修改。 C:\Program Files\Unity\Hub\Editor\2021.1.18f1c1\Editor\Data\PlaybackEngines\WebGLSupport\BuildTools\WebGLTemplates\Default再桌面新建一个t…

chatgpt大模型基础学习

chatgpt大模型基础学习 1. 吴恩达提示工程2. 大模型说的token是什么 1. 吴恩达提示工程 知乎 https://zhuanlan.zhihu.com/p/626290417?utm_id0 中文版 https://mp.weixin.qq.com/s?__bizMzkwMjQ5MzExMg&mid2247483714&idx1&sn5e905f5ec6196f6dc2187db2a8618f02&…

Jmeter接口测试,一篇足矣。

&#x1f345; 视频学习&#xff1a;文末有免费的配套视频可观看 &#x1f345; 关注公众号&#xff1a;互联网杂货铺&#xff0c;回复1 &#xff0c;免费获取软件测试全套资料&#xff0c;资料在手&#xff0c;涨薪更快 现在对测试人员的要求越来越高&#xff0c;不仅仅要做好…

使用强森算法求任意两点之间最短路径

对于强森算法的算法思想,如果给定的图中是没有负数的边,那么就可以使用迪杰斯特拉算法来进行遍历每个节点,找到它与其他节点的最短路径,而如果给定的图中是存在负数的边,但是不存在负数的环的时候,那么就可以使用算法对边长做一些修改并且可以准确的找到给定的两个节点之…

各种窗函数对脉压结果的影响

雷达导论专栏总目录链接: 雷达导论专栏总目录-CSDN博客 1. 各类窗函数 有几个窗函数的系数可配,配置如下: tukeywin(N,0.75)kaiser(N,2.5)gausswin(N,1.5)taylorwin(N,3,-24)2. 时域加窗 时域加窗时,直接加在匹配滤波函数上:Htw=exp(1j*pi*K*tp.^2).*win;。那么矩形窗就相…

手撕算法-最长公共子序列(二)

最长公共子序列(二) 分析&#xff1a;典型的动态规划&#xff0c;直接看代码了。 代码&#xff1a; import java.util.*;public class Solution {/*** 代码中的类名、方法名、参数名已经指定&#xff0c;请勿修改&#xff0c;直接返回方法规定的值即可** longest common sub…

【第十四章】改进神经网络学习方式-权重初始化

当我们创建神经网络时&#xff0c;我们必须为初始权重和偏置做出选择。到目前为止&#xff0c;我们一直根据我在第一章中简要讨论过的一种方法来选择它们。提醒一下&#xff0c;那种方法是使用独立的高斯随机变量来选择权重和偏置&#xff0c;使它们的均值为0&#xff0c;标准差…

从C++源代码到可执行文件?

从C源代码到可执行文件的转换是一个涉及多个步骤的过程&#xff0c;通常包括预处理、编译、汇编和链接四个主要阶段&#xff1a; 1.四个阶段 预处理 (Preprocessing) 预处理器&#xff08;如cpp&#xff09;首先读取原始的C源代码文件&#xff0c;并对其进行一系列文本替换操作…

【考研数学】武忠祥全年各阶段搭配用书汇总

如果选武忠祥&#xff0c;讲义方面选择基础篇和辅导讲义即可。分别在基础阶段和强化阶段使用。 此外复习全书不用买&#xff08;无论是基础篇还是提高篇都不用&#xff09;你以后可能会看到它的各种推广&#xff0c;不要轻信&#xff0c;有讲义的情况下全书很难利用得上。 武…

Positive Technologies 专家发现的漏洞已在 ABB 控制器中得到修复

&#x1f31f; 我们的同事一如既往地表现出色&#xff1a;应用分析专家 Natalia Tlyapova 和 Denis Goryushev 因发现 Freelance AC 900F 和 AC 700F 控制器中的两个漏洞而受到 ABB 的表彰。 这些设备用于自动化大规模连续循环生产设施和构建企业配送控制系统。利用这些漏洞的…

一文彻底搞懂TCP三次握手和四次挥手,及常见的面试题带答案

TCP&#xff08;传输控制协议&#xff09;是一种可靠的、面向连接的协议。在TCP/IP协议栈中&#xff0c;它负责在两个网络应用程序之间建立可靠的会话连接。TCP通过“三次握手”建立连接&#xff0c;通过“四次挥手”断开连接。本文将详细介绍这两个过程&#xff0c;并给出一些…

Women of Polkadot:波卡生态的女性社群与创新力量

在 Web3 行业里&#xff0c;女性似乎总是被忽视的群体。线下峰会的合照一眼望去尽是西装革履的男性成员&#xff0c;项目和机构高管的名单里也似乎难以寻觅到女性领导者的身影。在这个强调技术、编程、极客精神的行业里&#xff0c;女性身份的缺席看起来如此天生自然。 根据 B…