- 广度优先的实现
 - 力扣中常见的二叉树相关问题及基本解决方案
 
tips: 在解决问题时,先确保问题能解决,再去考虑效率,这是解题的关键,切不可为追求效率而变成了技巧性解答。
广度优先
广度优先(层序遍历)遍历的方式是按层次从上到下,从左到右的逐层访问。
[36, 21, 56, 8, 23, 38,72]

public void levelTraversal(TreeNode root) {
    Deque<TreeNode> queue = new ArrayDeque<>();
    if (root == null) return;
    queue.offer(root);
    while (!queue.isEmpty()) {
        TreeNode peek = queue.pop();
        System.out.println(peek.val);
        if (peek.left != null) {
            queue.offer(peek.left);
        }
        if (peek.right != null) {
            queue.offer(peek.right);
        }
    }
}
 
力扣问题
- 102. 二叉树的层序遍历 - 力扣(LeetCode)
 - 107. 二叉树的层序遍历 II - 力扣(LeetCode)
 
二叉树经典例题
计算二叉树的深度
问题
[LCR 175] LCR 175. 计算二叉树的深度 - 力扣(LeetCode)
问题描述
某公司架构以二叉树形式记录,请返回该公司的层级数。
示例 1:
 
输入:root = [1, 2, 2, 3, null, null, 5, 4, null, null, 4]
输出: 4
解释: 上面示例中的二叉树的最大深度是 4,沿着路径 1 -> 2 -> 3 -> 4 或 1 -> 2 -> 5 -> 4 到达叶节点的最长路径上有 4 个节点。
 
解决方案
 
参考实现
class Solution {
    public int calculateDepth(TreeNode root) {
        if(root == null) return 0;
        return Math.max(calculateDepth(root.left) , calculateDepth(root.right))+1;
    }
}
 
将有序数组转换为二叉搜索树
问题
108. 将有序数组转换为二叉搜索树 - 力扣(LeetCode)
问题描述
给你一个整数数组 nums ,其中元素已经按 升序 排列,请你将其转换为一棵
平衡二叉搜索树。
示例 1:

输入:nums = [-10,-3,0,5,9]
输出:[0,-3,9,-10,null,5]
解释:[0,-10,5,null,-3,null,9] 也将被视为正确答案:
 
示例 2:

输入:nums = [1,3]
输出:[3,1]
解释:[1,null,3] 和 [3,1] 都是高度平衡二叉搜索树。
 
解决方案
有序数组拆半放入二叉搜索树。
- 左边部分放入搜索树左侧
 - 右边部分放入搜索树右侧
 
 
参考实现
class Solution {
    public TreeNode sortedArrayToBST(int[] nums) {
        if (nums.length == 0) {
            return null;
        }
        int mid = nums.length / 2;
        TreeNode root = new TreeNode(nums[mid]);
        root.left = sortedArrayToBST(Arrays.copyOfRange(nums, 0, mid));
        root.right = sortedArrayToBST(Arrays.copyOfRange(nums, mid + 1, nums.length));
        return root;
    }
}
 
寻找二叉搜索树中的目标节点
题目
[LCR174] LCR 174. 寻找二叉搜索树中的目标节点 - 力扣(LeetCode)
题目描述
某公司组织架构以二叉搜索树形式记录,节点值为处于该职位的员工编号。请返回第 cnt 大的员工编号。
示例 1:
 
输入:root = [7, 3, 9, 1, 5], cnt = 2
       7
      / \
     3   9
    / \
   1   5
输出:7
 
示例 2:
 
输入: root = [10, 5, 15, 2, 7, null, 20, 1, null, 6, 8], cnt = 4
       10
      / \
     5   15
    / \    \
   2   7    20
  /   / \ 
 1   6   8
输出: 8
 
解决方案
中序解决排序问题
参考实现
class Solution {
    public int findTargetNode(TreeNode root, int cnt) {
        List<Integer> list = new ArrayList<Integer>();
        inOrder(root,list);
      //  System.out.println(list);
        return list.get(list.size()-cnt);
    }
    private void inOrder(TreeNode root,List<Integer> list){
        if(root ==null){
            return ;
        }
        inOrder(root.left,list);
        list.add(root.val);
        inOrder(root.right,list);
    }
}
 
计算布尔二叉树的值
题目
[力扣2331] 2331. 计算布尔二叉树的值 - 力扣(LeetCode)
题目描述
给你一棵 完整二叉树 的根,这棵树有以下特征:
- 叶子节点 要么值为 
0要么值为1,其中0表示False,1表示True。 - 非叶子节点 要么值为 
2要么值为3,其中2表示逻辑或OR,3表示逻辑与AND。 
计算 一个节点的值方式如下:
- 如果节点是个叶子节点,那么节点的 值 为它本身,即 
True或者False。 - 否则,计算 两个孩子的节点值,然后将该节点的运算符对两个孩子值进行 运算 。
 
返回根节点 root 的布尔运算值。
完整二叉树 是每个节点有 0 个或者 2 个孩子的二叉树。
叶子节点 是没有孩子的节点。
示例 1:
 
输入:root = [2,1,3,null,null,0,1]
输出:true
解释:上图展示了计算过程。
AND 与运算节点的值为 False AND True = False 。
OR 运算节点的值为 True OR False = True 。
根节点的值为 True ,所以我们返回 true 。
 
示例 2:
输入:root = [0]
输出:false
解释:根节点是叶子节点,且值为 false,所以我们返回 false 。
 
解决方案
递归根据情况进行分类。

参考实现
class Solution {
    public boolean evaluateTree(TreeNode root) {
        if(root.val ==1) return true;
        else if(root.val == 0) return false;
        else if(root.val ==2) return evaluateTree(root.left) || evaluateTree(root.right);
        else  return evaluateTree(root.left) && evaluateTree(root.right);
    }
}
 
二叉搜索树的范围和
问题
[力扣938] 938. 二叉搜索树的范围和 - 力扣(LeetCode)
问题描述
给定二叉搜索树的根结点 root,返回值位于范围 [low, high] 之间的所有结点的值的和。
示例 1:

输入:root = [10,5,15,3,7,null,18], low = 7, high = 15
输出:32
 
示例 2:

输入:root = [10,5,15,3,7,13,18,1,null,6], low = 6, high = 10
输出:23
 
解决方案
从根节点递归到叶节点的过程中,如果小于low,则走右侧(值的范围必须大于等于low)
如果大于high,则走左侧(值的范围必须小于等于high),
如果在范围内[low, high], 则继续遍历其子节点。
参考实现
放入List集合中,按照集合中数据的访问遍历。
class Solution {
    public int rangeSumBST(TreeNode root, int low, int high) {
        List<Integer>  list  = new ArrayList<>();
        inOrder(root, list);
        int sum=0;
        for(int t :  list){
            if(t >=low && t <=high){
                sum+=t;
            }
        }
        return sum;
    }
    private void inOrder(TreeNode root, List<Integer> list){
        if(root == null) return ;
        inOrder(root.left, list);
        list.add(root.val);
        inOrder(root.right, list);
    }
}
 
当前递归节点与low和high进行比较
- root< low : 说明左侧没有合适的值,那么继续递归右侧
 - root > right: 说明右侧没有合适的值,那么继续递归左侧
 - root 在范围之内,则将左侧和右侧的结果相加+ 当前节点的值。
 
class Solution {
    public int rangeSumBST(TreeNode root, int low, int high) {
        if(root == null) return 0;
        if(root.val < low){
            return rangeSumBST(root.right, low, high);
        }
        if(root.val > high){
            return rangeSumBST(root.left, low, high);
        }
        return rangeSumBST(root.left,low,high)
               + rangeSumBST(root.right,low,high)
               + root.val;
    }
}
 
二叉搜索树中第K小的元素
题目
230. 二叉搜索树中第 K 小的元素 - 力扣(LeetCode)
题目描述
给定一个二叉搜索树的根节点 root ,和一个整数 k ,请你设计一个算法查找其中第 k 小的元素(从 1 开始计数)。
示例 1:

输入:root = [3,1,4,null,2], k = 1
输出:1
 
示例 2:

输入:root = [5,3,6,2,4,null,null,1], k = 3
输出:3
 
解决方案
中序遍历存入list集合
找到list中的第k小项
参考实现
class Solution {
    public int kthSmallest(TreeNode root, int k) {
     List<Integer> list = new ArrayList<>();   
     inOrder(root,list);
    return list.get(k-1);
    }
    private void inOrder(TreeNode root,List<Integer> list){
        if(root==null) return ;
        inOrder(root.left, list);
        list.add(root.val);
        inOrder(root.right,list);
    }
}
 
二叉搜索树中的中序后继
题目
[力扣LCR053] LCR 053. 二叉搜索树中的中序后继 - 力扣(LeetCode)
题目分析
给定一棵二叉搜索树和其中的一个节点 p ,找到该节点在树中的中序后继。如果节点没有中序后继,请返回 null 。
节点 p 的后继是值比 p.val 大的节点中键值最小的节点,即按中序遍历的顺序节点 p 的下一个节点。
示例 1:

输入:root = [2,1,3], p = 1
输出:2
解释:这里 1 的中序后继是 2。请注意 p 和返回值都应是 TreeNode 类型。
 
示例 2:

输入:root = [5,3,6,2,4,null,null,1], p = 6
输出:null
解释:因为给出的节点没有中序后继,所以答案就返回 null 了。
 
解决方案
- 中序记录在List集合中,找到p在list中的位置索引,如果索引>=0 || 不是最后一个位置则返回,否则返回null。
 - 记录上一个节点pre, 当前curr。
 
参考实现
class Solution {
    public TreeNode inorderSuccessor(TreeNode root, TreeNode p) {
        Stack<TreeNode> stack = new Stack<>();
        TreeNode curr = root;
        TreeNode pre = null;
        while(curr!=null || !stack.isEmpty()){
            while(curr!=null){
                stack.push(curr);
                curr = curr.left;
            }
           curr = stack.pop();
           if(pre == p){
             return   curr;
           }
           pre = curr;
           curr = curr.right;
        }
        return null;
    }
}
 
两数之和IV-输入二叉搜索树
问题
[力扣653] 653. 两数之和 IV - 输入二叉搜索树 - 力扣(LeetCode)
问题描述
给定一个二叉搜索树 root 和一个目标结果 k,如果二叉搜索树中存在两个元素且它们的和等于给定的目标结果,则返回 true。
示例 1:

输入: root = [5,3,6,2,4,null,7], k = 9
输出: true
 
示例 2:

输入: root = [5,3,6,2,4,null,7], k = 28
输出: false
 
解决方案
- 将数据存入一个List集合
 - 问题转换为找到一个集合中的和为K的两个数。
 
参考实现
class Solution {
    public boolean findTarget(TreeNode root, int k) {
        Map<Integer, Integer> map = new HashMap<>();
        List<Integer> list = new ArrayList<>();
        final int DEFAULT_VAL = 999;
        inOrder(root, list);
        //System.out.println(list);
        for(int t : list){
            int target = k - t;
            if(map.containsKey(target)){
                return true;
            }
            map.put(t, DEFAULT_VAL);
        }
        return false;
    }
    private void inOrder(TreeNode root, List<Integer> list) {
        if (root == null) return ;
        inOrder(root.left, list);
        list.add(root.val);
        inOrder(root.right, list);
    }
}
 
class Solution {
    public boolean findTarget(TreeNode root, int k) {
        Map<Integer,Integer> map = new HashMap<>();
        List<TreeNode> stack  = new ArrayList<>();
        TreeNode curr = root;
        while(curr!=null || !stack.isEmpty()){
            while(curr!=null){
                int target= k - curr.val;
                if(map.containsKey(target)){
                    return true;
                }
                map.put(curr.val,999);
                stack.add(curr);
                curr = curr.left;
            }
            curr = stack.remove(stack.size()-1);
            curr = curr.right;
        }
        return false;
    }
}
                

















