二叉树专题总结

二叉树的总结


基本知识:二叉树是一种天然的递归数据结构,这个章节一定要掌握递归的写法,但是面试经常反套路,喜欢问迭代的写法(就是就是将递归的过程用栈模拟出来)
二叉树的三种遍历:
前序:根-左-右
中序:左-根=右
后序:左-右-根
写递归的时候牢记递归三要素

94. 二叉树的中序遍历(递归+迭代)

/**
 * 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<Integer> inorderTraversal(TreeNode root) {
        List<Integer> res = new ArrayList<>();
        // 特判
        if(root == null) return res;
        // 调用递归
        inorder(root,res);
        // 返回结果
        return res;

        

    }
    public void inorder(TreeNode root,List<Integer> res){
        // 递归出口
        if(root == null) return;
        // 递归左子树
        inorder(root.left,res);
        // 根
        res.add(root.val);
        // 递归右子树
        inorder(root.right,res);
    }
}

中序遍历迭代法:

/**
 * 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<Integer> inorderTraversal(TreeNode root) {
        // 递归的本质是使用一个栈来维护历史记录信息
        // 所以我们可以使用栈来模拟
        Stack<TreeNode> stack = new Stack<>();
        List<Integer> res = new ArrayList<>();
        // 特判
        if(root == null) return res;
        // 栈内不空或者root非空的时候
        while(root != null || !stack.isEmpty()){
            // 中序遍历:左-根-右
            // 所以我们要模拟走到最左边的情况
            if(root != null){
                // 路劲添加到栈中
                stack.add(root);
                // 往左走
                root = root.left;
            }else{
                // 根节点空了,说明要弹出栈顶节点,然后往右边走
                root = stack.pop();
                // 记录到结果中
                res.add(root.val);
                // 往右边走
                root = root.right;
            }
        }
        return res;   
    }

}

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 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);

    }
}

101. 对称二叉树(改造dfs)

/**
 * 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) {
        /**
        分析:
        本题的核心是找到对称的数学解决办法,所谓二叉树对称,就是节点的左子树等于节点的右子树。
        说到等于,不就是上一题的相等二叉树,那么这边需要做一下处理的是   镜像等于,关注镜像二字
         */
         // 特判
         if(root == null) return true;
         // 调用递归代码
         // 设计两个树 来处理镜像
         return dfs(root,root);


    }
    public boolean dfs(TreeNode p,TreeNode q){
        // 递归出口
        if(p == null && q == null) return true;
        else if(p == null || q == null) return false;
        else if( p.val != q.val) return false;
        // 一个节点的左子节点 和镜像节点的右子节点比较
        // 然后再比较右子节点和镜像节点的 左子节点
        return dfs(p.left,q.right) && dfs(p.right,q.left);
    }
}

102. 二叉树的层序遍历(层序遍历模板)

/**
 * 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<List<Integer>> levelOrder(TreeNode root) {
        /**
        分析:
        记住层序遍历代码模板即可,层序遍历是使用队列的
         */
        List<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();
            // 记录当前层的结果
            List<Integer> temp = new ArrayList<>();
            // 遍历当前层
            for(int i = 0; i < size; i++){
                // 取队头
                TreeNode cur = queue.poll();
                // 加入当前层结果
                temp.add(cur.val);
                // 判断左右子节点
                if(cur.left != null) queue.offer(cur.left);
                if(cur.right != null) queue.offer(cur.right);
            }
            // 当前层加入结果中
            res.add(temp);
        }
        return res;
    }
    
}

103. 二叉树的锯齿形层序遍历(加了一个标签的层序遍历)

/**
 * 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<List<Integer>> zigzagLevelOrder(TreeNode root) {
        /**
        分析:
        奇数层 顺序遍历, 偶数层 逆序遍历
         这里使用int 类型储存奇数偶数层次,使用ArrayList 的add重载方法,实现数据的头插尾插(实际上也可以使用LinkedList的offerFirst 和 offerLast)
         */
         List<List<Integer>> res = new ArrayList<>();
         if(root == null) return res;
         Queue<TreeNode> queue = new LinkedList<>();
         queue.offer(root);
         int level = 0;
         while( !queue.isEmpty()){
             int size = queue.size();
            //  List<Integer> temp = new ArrayList<>();
            // LinkedList
            LinkedList<Integer> temp = new LinkedList<>();
             for(int i = 0; i< size; i++){
                 TreeNode cur = queue.poll();
                 if(level % 2 == 0){
                    //  temp.add(cur.val);
                    temp.offerLast(cur.val);
                 }else{
                     // 代表每次添加都添加到下标为0的位置,原来位置和后面位置都翔右边移动
                    //  temp.add(0,cur.val);
                    temp.offerFirst(cur.val);
                 }
                 if(cur.left!=null) queue.offer(cur.left);
                 if(cur.right!=null) queue.offer(cur.right);
             }
             res.add(temp);
             // 层数累加
             level++;
         }
         return res;


    }
}

107. 二叉树的层序遍历 II(使用api)

/**
 * 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<List<Integer>> levelOrderBottom(TreeNode root) {
        /**
        分析:
        使用LinkedList中 offerFirst API即可完成操作
        还可以使用正常的加入操作,最后结果反转一下 Collections.reverse(res);
         */
         LinkedList<List<Integer>> res = new LinkedList<>();
         if(root == null) return res;
         Queue<TreeNode> queue = new LinkedList<>();
         queue.offer(root);
         while( !queue.isEmpty()){
             int size = queue.size();
             List<Integer> temp = new ArrayList<>();
             for(int i = 0; i < size; i++){
                 TreeNode cur = queue.poll();
                 temp.add(cur.val);
                 if(cur.left != null) queue.offer(cur.left);
                 if(cur.right != null) queue.offer(cur.right);
             }
             res.offerFirst(temp);
         }
         return res;


    }
}

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 int maxDepth(TreeNode root) {
        /**
        分析:
        深度问题可以理解成左子树深度和右子树的深度取最大值
         */
         // 后序遍历法
         // 递归出口
         if(root == null) return 0;
         int left = maxDepth(root.left);
         int right = maxDepth(root.right);
         // 处理根节点
         return Math.max(left,right) + 1;

    }
}

110. 平衡二叉树(计算树高)

/**
 * 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就是符合题意的,很明显这是一个递归的过程.
        刚开始做的时候陷入沉思,我该怎么求子树的高度啊?只有求出子树的高度我才可以进行比较判断。
        这就和求二叉树的最大深度那一题很像了,那么我们就可以得到子树高度。
        如何关联平衡二叉树和子树高度? 定义一个节点是否是平衡二叉树 -》 判定该节点的高度是否为-1(是-1则不是平衡二叉树)
         */
         // 若节点不是-1,则是平衡二叉树
         return height(root) != -1;
    }
    public int height(TreeNode root){
        /**
        和计算二叉树深度那题很像
         */
         if(root == null) return 0;
         
         int left = height(root.left);
         // 如果左子树出现不是平衡树
         if(left == -1) return -1;

         int right = height(root.right);
         // 如果右子树出现不是平衡树
         if(right == -1) return -1;
         // 处理本节点
         // 若子树高度差绝对值小于2 那么就是平衡二叉树,更新节点高度,否则节点高度设置为-1
         return Math.abs(left - right) < 2 ? Math.max(left,right) + 1 : -1;

    }
}

111. 二叉树的最小深度(计算树高)

使用dfs

/**
 * 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) {
        /**
        分析:
        核心还是在求树的高度
         */
         // 使用后序遍历
         if( root == null) return 0;
         // 求左子树 树高
         int left = minDepth(root.left);
         // 求右子树 树高
         int right = minDepth(root.right);
         // 若左右子树有一个是0 那么树高就是不为0的子树+1
         // 若左右子树都不为0,那么树高就是取最小值然后+1
         return (left == 0 || right == 0) ? left + right + 1: Math.min(left,right) + 1;

    }
}

使用bfs

class Solution {
    public int minDepth(TreeNode root) {
        // 使用bfs 所谓的树高就是层数
        if(root == null) return 0;
        Queue<TreeNode> queue = new LinkedList<>();
        queue.offer(root);
        int level = 0;
        while( !queue.isEmpty()){
            int size = queue.size();
            level++;
            for(int i = 0; i < size; i++){
                TreeNode cur = queue.poll();
                if(cur.left == null && cur.right == null){
                    return level;
                }
                if(cur.left != null) queue.offer(cur.left);
                if(cur.right != null) queue.offer(cur.right);
            }
        }
        return 0;

    }
}

144. 二叉树的前序遍历

/**
 * 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 {
    List<Integer> res = new ArrayList<>();
    public List<Integer> preorderTraversal(TreeNode root) {
        if(root == null) return res;
        preorder(root);
        return res;
    }
    public void preorder(TreeNode root){
        if(root == null) return;
        res.add(root.val);
        preorder(root.left);
        preorder(root.right);
        return ;
    }
}

199. 二叉树的右视图(DFS+BFS)

使用BFS,比较容易想到

/**
 * 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<Integer> rightSideView(TreeNode root) {
        /**
        分析:
        解法一:BFS,实际上就是求队列中的最后一个节点
        解法二:DFS,先序遍历是根-左-右,首先访问左节点,那么本题是要求首先访问右节点,所以重写先序遍历为根-右-左,在遍历的时候,如果树高等于结果集个数,说明这个是该层的第一个访问节点,那么直接加入
         */
         // 使用BFS
         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 temp = queue.poll();
                // 判断是否是该层最后一个节点
                if( i == size - 1){
                    res.add(temp.val);
                }
                if(temp.left!=null) queue.offer(temp.left);
                if(temp.right!=null) queue.offer(temp.right);
             }
         }
        return res;
    }
}

使用DFS,比较难想到

class Solution {
    public List<Integer> rightSideView(TreeNode root) {
        // 使用DFS
        List<Integer> res = new ArrayList<>();
        if(root == null) return res;
        preOrder(root,0,res);
        return res;
    }
    public void preOrder(TreeNode root,int depth,List<Integer> res ){
        if(root == null) return ;
        // 判断结果集中的个数和层数是否一一对应
        if(res.size() == depth){
            res.add(root.val);
        }
        // 右边递归 深度+1
        preOrder(root.right, depth+1,res);
        // 左边递归 深度+1
        preOrder(root.left,depth+1,res);
        

    }
}

404. 左叶子之和(DFS+bfs)

dfs:

class Solution {
    int sum = 0;
    public int sumOfLeftLeaves(TreeNode root) {
        if(root == null) return 0;
        dfs(root);
        return sum;
    }
    public void dfs(TreeNode root){
        if(root == null) return ;
        // 这个思路很简单,先判断左子节点,然后判断左子节点是否是 叶子节点
        if(root.left != null && root.left.left == null && root.left.right == null) sum += root.left.val;
        dfs(root.left);
        dfs(root.right);
    }
}

上面代码转换为BFs也是同样逻辑,先判断左子节点,然后判断是否是叶子节点

class Solution {
    int sum = 0;
    public int sumOfLeftLeaves(TreeNode root) {
        if(root == null) return 0;
        Queue<TreeNode> queue = new LinkedList<>();
        queue.offer(root);
        while( !queue.isEmpty()){
            int size = queue.size();
            for(int i = 0 ; i < size; i++){
                TreeNode temp = queue.poll();
                if(temp.left != null){
                    // 判断是否是叶子
                    if(isLeafnode(temp.left)){
                        sum += temp.left.val;
                    }else{
                        // 进入队列
                        queue.offer(temp.left);
                    }
                }
                // 右叶子不需要进队
                if( temp.right!=null && !isLeafnode(temp.right)){
                    queue.offer(temp.right);
                }
            }
        }
        return sum;
    }
    public boolean isLeafnode(TreeNode root){
        return root.left == null && root.right == null;
    }

515. 在每个树行中找最大值(BFS)

/**
 * 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<Integer> largestValues(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();
            //  PriorityQueue<TreeNode> pq = new PriorityQueue<>((a,b) -> b.val - a.val);
            int maxValue = Integer.MIN_VALUE;
             for(int i = 0; i < size; i++){
                 TreeNode temp = queue.poll();
                //  pq.add(temp);
                maxValue = Math.max(maxValue,temp.val);
                 if(temp.left != null) queue.offer(temp.left);
                if(temp.right != null) queue.offer(temp.right);
             }
            //  res.add(pq.remove().val);
            res.add(maxValue);
             
         }
         return res;

    }
}

543. 二叉树的直径(dfs)

/**
 * 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 {
    int ans = 0;
    public int diameterOfBinaryTree(TreeNode root) {
        /**
        分析:
        二叉树直径必定会重复经过一个节点,设定一个节点的值为左右子树最大高度和。
        遍历每一个节点,以每一个节点为中心点计算最长路径(左子树边长+右子树边长),更新全局变量max。
         */
         if(root == null) return 0;
         dfs(root);
         return ans;
    }
    public int  dfs(TreeNode root){
        if(root == null) return 0;
        int left = dfs(root.left);
        int right = dfs(root.right);
        // 更新结果
        ans = Math.max(ans,left+right);
        // 处理根节点
        return Math.max(left,right) +1;

    }
}

112. 路径总和(dfs+bfs)

/**
 * 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 {
    List<Integer> res = new ArrayList<>();
    public boolean hasPathSum(TreeNode root, int targetSum) {
        /**
        分析:
        直接想法是把路劲总和放在一个 容器里面,然后遍历容器 判断是否存在总和
         */
        //  if(root == null) return false;
        //  // 求路劲和,需要一个参数:父亲节点的路径和(初始化为0)
        //  dfs(root,0);
        //  for(int sum:res){
        //      if(sum == targetSum){
        //          return true;
        //      }
        //  }
        //  return false;

        // 第一种思路是“加法思想”,另一种思想是减法思想
        // if(root == null) return false;
        // if(root.left == null && root.right == null){
        //     return targetSum - root.val == 0;
        // }
        // // 只要左右子树 有一个满足就返回
        // return hasPathSum(root.left,targetSum - root.val) || hasPathSum(root.right,targetSum - root.val);

        // 试试使用BFS来解决问题
        if(root == null) return false;
        Queue<TreeNode> queueNode = new LinkedList<>();
        Queue<Integer> queueSum = new LinkedList<>();
        queueNode.offer(root);
        queueSum.offer(root.val);
        // 正常的BFS判断还是使用 queueNode
        while( !queueNode.isEmpty()){
            TreeNode cur = queueNode.poll();
            int temp = queueSum.poll();
            // 判断是否叶子节点
            if( cur.left == null && cur.right == null){
                // 取出的temp值等于targetSum 说明找到了
                if(temp == targetSum){
                    return true;
                }
            }
            // 左边去遍历
            if(cur.left != null){
                queueNode.offer(cur.left);
                // 添加的是原来的temp值和左子节点值的和
                queueSum.offer(temp + cur.left.val);
            }
            if(cur.right != null){
                queueNode.offer(cur.right);
                // 添加的是原来的temp值和右子节点值的和
                queueSum.offer(temp + cur.right.val);
            }
        }
        return false;
        
    }
    // public void dfs(TreeNode root,int parentPathSum){
    //     if(root == null) return ;
    //     // 当前节点值
    //     int curSum = parentPathSum + root.val;
    //     // 遇到叶子节点
    //     if(root.left == null && root.right == null){
    //         res.add(curSum);
    //     }
    //     dfs(root.left,curSum);
    //     dfs(root.right,curSum);

    // }
}

113. 路径总和 II(dfs)

/**
 * 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 {
    // 定义全局结果集
    List<List<Integer>> res = new ArrayList<>();
    // 定义路径
    List<Integer> path = new ArrayList<>();
    public List<List<Integer>> pathSum(TreeNode root, int targetSum) {
        if(root == null) return res;
        // 添加路径
        path.add(root.val);
        // 遇到叶子节点
        if(root.left == null && root.right == null){
            // 恰好是targetSum减法减完了
            if( targetSum - root.val == 0){
                // 将路劲添加到 res中
                // 这里不能直接 使用 res.add(path),因为添加path对象的话,path对象是一直变化的,那么导致res中的对象也是一直变化的
                // 所以这里确定完路径后,就要将path写死到res中
                res.add(new ArrayList<>(path));
            }
        }
        // 递归做减法
        pathSum(root.left,targetSum - root.val);
        // 递归做减法
        pathSum(root.right,targetSum - root.val);
        // 回朔 将当前节点从path中删除
        path.remove(path.size() - 1);
        return res;
    }
}

114. 二叉树展开为链表(dfs)

/**
 * 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 {
    List<TreeNode> res = new ArrayList<>();
    public void flatten(TreeNode root) {
        /**
        最简单的思路就是使用前序遍历储存节点信息到一个list中,然后root节点按照list修改
         */
         if( root == null ) return ;
         preOrder(root);
         // 遍历list
         for(int i = 1; i < res.size(); i++){
             // 前驱节点
             TreeNode pre = res.get( i - 1);
             // 后继节点
             TreeNode next = res.get(i);
             pre.left = null;
             pre.right = next;
         }


    }
    public void preOrder(TreeNode root){
        if(root == null) return ;
        res.add(root);
        preOrder(root.left);
        preOrder(root.right);
    }
}

124. 二叉树中的最大路径和(和543那一题是一模一样其实关键就是读懂题意)

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-7NdlX3nj-1637633734738)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20211123100245309.png)]

/**
 * 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 {
    // 全局变量
    int maxSum = Integer.MIN_VALUE;
    public int maxPathSum(TreeNode root) {
        /**
        分析:
        这道题的难点在于读懂题意,这里的路径可以是:1.根 2 根-左 3.根-右 4.左-根-右 5.左 6.右
        为什么会有 1.5.6的存在呢?因为节点有可能是负数的,这时候还不如不加上去。
        基于上面的分析,我们可以递归解决。
         */
         // root 不为空
         dfs(root);
         return maxSum;
    }
    public int dfs(TreeNode root){
        if(root == null) return 0;
        // 计算左右子树的贡献值,这里的贡献值有可能是负数(那就不要加上去,用0代替)
        int leftGain = Math.max(0,dfs(root.left));
        int rightGain = Math.max(0,dfs(root.right));
        // 处理 maxsum,注意这里的贡献值已经设置成了 >=0 
        maxSum = Math.max(maxSum,leftGain + rightGain + root.val);
        // 处理当前节点:左右子树最大贡献值+根节点(因为题目规定不能分叉,同一个节点在一条路径序列中 至多出现一次)
        return Math.max(leftGain,rightGain) + root.val;
    }
}

222. 完全二叉树的节点个数(dfs+bfs)

题解中使用了 完全二叉树的性质,以及位运算,能力检测二分法(个人觉得这题的难度已经是困难题了,没有必要深入研究,掌握基础解法就可以)
使用BFS

/**
 * 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 {
    int res = 0;
    public int countNodes(TreeNode root) {
        if( root == null) return 0;
        Queue<TreeNode> queue = new LinkedList<>();
        queue.offer( root );
        while( !queue.isEmpty() ){
            int size = queue.size();
            for(int i = 0; i < size; i++){
                res++;
                TreeNode cur = queue.poll();
                if( cur.left != null){
                    queue.offer( cur.left );
                }
                if( cur.right != null){
                    queue.offer( cur.right );
                }
            }
        }
        return res;
    }
}

使用后序遍历DFS

class Solution {
    public int countNodes(TreeNode root) {
        return root == null ? 0 : countNodes(root.left) + countNodes(root.right) + 1;
    }
}

236. 二叉树的最近公共祖先(后续dfs,回溯思想)

/**
 * Definition for a binary tree node.
 * public class TreeNode {
 *     int val;
 *     TreeNode left;
 *     TreeNode right;
 *     TreeNode(int x) { val = x; }
 * }
 */
class Solution {
    public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) {
        /**
        分析:
        若 p 和 q不在同一个子树上,那么结果就是 连接两个子树的根节点
        若 p 和 q在同一个子树上,那么结果就是 高度低的那个节点
        ==============================================================
        上面的思路其实跑偏了,正确的思路应该是采用自底向上遍历(回溯的思想),后续遍历就是天然的回溯
         */
         // 遇到空节点
         if( root == null) return null;
        // 遇到了p或者q,那么向上返回该节点
         if(root == p || root == q) return root;
         // 递归遍历 左子树
         TreeNode left = lowestCommonAncestor(root.left,p,q);
         // 递归遍历 右子树
         TreeNode right = lowestCommonAncestor(root.right,p,q);
         // 回溯的代码
         // 若 左右子树不空,那么此时的根就是 最近祖先
        //  if( left != null && right != null) return root;
         // 若左子树为空, 那么应该向上返回右子树节点的 祖先
         if( left == null) return right;
         if( right == null) return left;
         return root;
    }
}

257. 二叉树的所有路径(回溯的思想)

第一次做思路是对的,就是这个String.join()api不知道怎么用

/**
 * 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 {
    List<String> res = new ArrayList<>();
    List<String> path = new ArrayList<>();
    public List<String> binaryTreePaths(TreeNode root) {
        if( root == null ) return res;
        dfs(root);
        return res;
    }
    public void dfs(TreeNode root){
        if(root == null) return;
        path.add(String.valueOf(root.val));
        if( root.left == null && root.right == null) {
            // 这里使用 了 String.join()用于连接 ->
            res.add( String.join("->", path));
        }
        dfs(root.left);
        dfs(root.right);
        // 回溯
        path.remove(path.size() - 1);
    }
}

437. 路径总和 III(dfs+前缀和)

使用了双重递归,一个递归用来 搜索所有节点,另一个递归用来记录路径和

/**
 * 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 {
    int res = 0;
    public int pathSum(TreeNode root, int targetSum) {
        /**
        分析:题目不是要求从根节点出发,这就加大了难度。
        本题学了一个新的骚操作,双重递归,一个递归用来搜索所有的节点,另一个递归用来记录路径和
         */
         if(root == null) return 0;
         // 使用先序遍历
         // 先在某一个节点上搜索 所有满足条件的路径
         helper(root,targetSum);
         pathSum(root.left,targetSum);
         pathSum(root.right,targetSum);
         return res;
    }
    public void helper(TreeNode root,int targetSum){
        if(root == null) return;
        targetSum -= root.val;
        // 搜索到满足的条件
        if(targetSum == 0) res++;

        helper(root.left,targetSum);
        helper(root.right,targetSum);
    }
}

或者使用前缀和思想,像这种一般不从root节点出发的,从中间开始的,都会使用前缀和,而前缀和套路经常是使用一个map来记录前缀和以及相应的个数(记得初始化前缀和,map.put(0,1) )

class Solution {
    public int pathSum(TreeNode root, int targetSum) {
        // 使用前缀和
        if( root == null ) return 0;
        Map<Integer,Integer> prefixSum = new HashMap<>();
        // 前缀和初始化,root节点有可能就是targetSum
        prefixSum.put(0,1);
        return dfs(root,prefixSum,0,targetSum);
    }
    public int dfs(TreeNode root,Map<Integer,Integer> prefixSum,int curSum,int targetSum){
        if(root == null ) return 0;
        int res = 0;
        // 更新当前和
        curSum += root.val;
        
        // 更新res
        res += prefixSum.getOrDefault(curSum - targetSum, 0);
        // 更新路径上当前节点前缀和的个数
        prefixSum.put(curSum, prefixSum.getOrDefault(curSum, 0) + 1);
        // 递归更新
        res += dfs(root.left, prefixSum, curSum, targetSum);
        res += dfs(root.right, prefixSum, curSum, targetSum);

        // 4.回到本层,恢复状态,去除当前节点的前缀和数量
        prefixSum.put(curSum, prefixSum.get(curSum) - 1);
        return res;

    }

}

662. 二叉树最大宽度(BFS)

/**
 * 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 widthOfBinaryTree(TreeNode root) {
        /**
        分析:
        按照常规思路是层序遍历,然后每层使用Math.max取到最大值,但是会发现这种算法是不会计算空节点。使用BFS还得计算空节点,那么第一想法是获取该层的一个元素编码和最后一个元素编码,该层个数就是 最后一个元素编码 - 第一个元素编码 + 1,每层再使用Math.max一下.
        这里的编码思想就是利用满二叉树的性质:父节点编号是 i(>=1) 那么 左子节点编号就是 2 * i,右子节点编号就是 2 * i + 1
         */
         if( root == null ) return 0;
         // 回去队列的第一个编码和最后一个编码,所以只能使用LinkedList定义队列了
         LinkedList<TreeNode> queue = new LinkedList<>();
         queue.offer(root);
         // 重新设置val,也就是编码值
         root.val = 1;
         // 定义宽度
         int maxWidth = 0;
         while( !queue.isEmpty() ){
             int size = queue.size();
             // 定义本层宽度
             int width = queue.getLast().val - queue.getFirst().val + 1; 
             for(int i = 0; i < size; i++){
                 TreeNode cur = queue.poll();
                 if(cur.left != null){
                     // 更新左节点编码
                     cur.left.val = 2 * cur.val;
                     queue.offer(cur.left);
                     
                 }
                 if(cur.right != null){
                     // 更新右节点编码
                     cur.right.val = 2 * cur.val + 1;
                     queue.offer(cur.right);
                 }
             }
             maxWidth = Math.max(maxWidth,width);
         }
        return maxWidth;
    }
}

98. 验证二叉搜索树(dfs)

下面的思路是按照题目直观的提示

/**
 * 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 isValidBST(TreeNode root) {
        if( root == null ) return false;
        return dfs(root,Long.MIN_VALUE,Long.MAX_VALUE);
    }
    public boolean dfs(TreeNode root,long lower,long higher){
        // 观察可以知道,左子树节点是小于 根节点值,右子树节点是大于 根节点值的
        if(root == null) return true;
        if(root.val <= lower || root.val >= higher) return false;
        // root的节点值作为上界
        boolean left = dfs(root.left,lower,root.val);
        // 进行剪枝操作
        if(!left) return false;
        // root的节点值作为下界
        boolean right = dfs(root.right,root.val,higher);
        // 进行剪枝操作
        if(!right) return false;
        return left && right;
        
    }
}

实际上我们可以利用二叉搜索树的性质,也就是中序遍历是递增的,先储存到一个列表中,然后依次判断是否递增。

class Solution {
    List<TreeNode> res = new ArrayList<>();
    public boolean isValidBST(TreeNode root) {
        // if( root == null ) return false;
        // return dfs(root,Long.MIN_VALUE,Long.MAX_VALUE);

        // 使用中序遍历
        if( root == null ) return false;
        // 构造中序遍历list
        inOrder(root);
        // 判断
        for(int i = 1; i < res.size(); i++){
            if( res.get(i).val <= res.get( i - 1).val ){
                return false;
            }
        }
        return true;
    }
    // 中序遍历
    public void inOrder(TreeNode root){
        if(root == null) return;
        inOrder(root.left);
        res.add(root);
        inOrder(root.right);
    }
}

99. 恢复二叉搜索树(中序遍历)

/**
 * 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 {
    List<TreeNode> res = new LinkedList<>();
    TreeNode x = null,y = null;
    public void recoverTree(TreeNode root) {
        /**
        分析:
        一旦看到二叉搜索树,就要想到中序遍历啊,那么我们完全可以使用将树中序遍历一下,储存到一个list中,然后去list中找到不是升序的哪两个节点,将这两个节点值互换
         */
         if(root == null ) return;
         dfs(root);
         for(int i = 1; i < res.size(); i++){
             if(res.get(i - 1).val > res.get(i).val){
                 // x 值更新一次
                 if( x == null) x = res.get(i - 1);
                 // y 也只更新一次
                 y = res.get(i);
             } 
         }
         // 交换节点值
         int temp = x.val;
         x.val = y.val;
         y.val = temp;
    }
    public void dfs(TreeNode root){
        if(root == null) return;
        dfs(root.left);
        res.add(root);
        dfs(root.right);
    }
}

105. 从前序与中序遍历序列构造二叉树(构建全局变量+hashmap)

/**
 * 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 {
    int rootIndex = 0;
    Map<Integer,Integer> map = new HashMap<>();
    int[] preorder;
    public TreeNode buildTree(int[] preorder, int[] inorder) {
        /**
        分析:
        首先要清除前序遍历:根-左-右,中序遍历:左-根-右
        前序遍历的第一个节点必是根节点,后面的区间为左右子树节点
        根据前序遍历的那个根节点找到了中序遍历该节点所在的位置,位置左边区间为根节点左子树,位置右边区间为根节点右子树。
        依次重复递归上述的左右子树,最后构造出一个完整的二叉树。
        这里有一个注意点就是:前序遍历和中序遍历均无重复元素。那么就可以使用hashmap储存中序遍历的值,实现中序数组的一次遍历(键是数组值,值是下标)
        可以将前序数组,hashmap,前序数组下标都设置为全局变量。
         */
         // 将前序数组设置为全局变量
         this.preorder = preorder;
         // 中序数组储存到哈希表中
         for(int i = 0; i < inorder.length; i++){
             // 数组都是无重复元素,所以可以大胆储存
             map.put(inorder[i],i);
         }
         // 构建二叉树
         return buildTree(0,inorder.length - 1);
    }
    public TreeNode buildTree(int left,int right){
        // 终止条件
        if( left > right){
            return null;
        }
        // 取根节点值 --- 前序数组
        int rootVal = preorder[rootIndex];
        rootIndex++;
        TreeNode root = new TreeNode(rootVal);
        // 构建左右子树
        // 获取中序遍历中根节点所在下标
        int mid = map.get(rootVal);
        root.left = buildTree(left,mid - 1);
        root.right = buildTree(mid + 1,right);
        return root;
    }
}

106. 从中序与后序遍历序列构造二叉树(和上一题样的套路,区别在于是右子树作为根节点了)

/**
 * 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 {
    Map<Integer,Integer> map = new HashMap<>();
    int[] postorder;
    int rootIndex;
    public TreeNode buildTree(int[] inorder, int[] postorder) {
        // 套用上一题的思想
        this.postorder = postorder;
        this.rootIndex = postorder.length - 1;
        for(int i = 0; i < inorder.length; i++){
            map.put(inorder[i],i);
        }
        return buildTree(0,inorder.length - 1);
    }
    public TreeNode buildTree(int left,int right){
        if(left > right){
            return null;
        }
        int rootVal = postorder[rootIndex];
        rootIndex--;
        TreeNode root = new TreeNode(rootVal);
        int mid = map.get(rootVal);
        // 右子树作为根节点
        root.right = buildTree(mid+1,right);
        root.left = buildTree(left,mid - 1);
        return root;
    }
}

108. 将有序数组转换为二叉搜索树(处理高度平衡的问题)

/**
 * 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 TreeNode sortedArrayToBST(int[] nums) {
        /**
        分析:题目给的是升序数组==》中序遍历结果
        一个中序遍历是无法确定一颗二叉树的。后面又给了一个条件,高度平衡。这个条件也是无法确定一个唯一的二叉树,但是可以满足题目的要求。
        如何实现高度平衡?每次的根节点都取中序数组的中间节点,递归创建就可以!
         */
         return buildBFS(nums,0,nums.length - 1);
    }
    public TreeNode buildBFS(int []nums,int left,int right){
        if(left > right) return null;
        // 取根节点
        int mid = left + (right - left) / 2;
        TreeNode root = new TreeNode(nums[mid]);
        // 递归建立左右子树
        root.left = buildBFS(nums,left,mid - 1);
        root.right = buildBFS(nums,mid + 1,right);
        // 处理本层
        return root;
    }
}

116. 填充每个节点的下一个右侧节点指针(BFS)

使用层序遍历,思路简单

/*
// Definition for a Node.
class Node {
    public int val;
    public Node left;
    public Node right;
    public Node next;

    public Node() {}
    
    public Node(int _val) {
        val = _val;
    }

    public Node(int _val, Node _left, Node _right, Node _next) {
        val = _val;
        left = _left;
        right = _right;
        next = _next;
    }
};
*/

class Solution {
    public Node connect(Node root) {
        /**
        分析:填充next指针,很容易想到层序遍历
         */
        if(root == null) return null;
        Queue<Node> queue = new LinkedList<>();
        queue.offer(root);
        while( !queue.isEmpty() ){
            int size = queue.size();
            for(int i = 0; i < size; i++){
                Node cur = queue.poll();
                Node next = null;
                // 若i不是当前层最后一个节点,就设置next,并指向next
                // 因为队列里面不断加入新元素,所以只能通过 i 和 size -1的关系来判断什么时候修改next
                if( i != size - 1){
                    next = queue.peek();
                    // 修改next指针
                    cur.next = next;
                }
                
                // 进队
                if( cur.left != null) queue.offer(cur.left);
                if( cur.right != null) queue.offer(cur.right);
            }
        }
            
        return root;
    }
}

使用dfs,比较难想到,就是其中的next之间的关系
// 每个 node 左子树的 next , 就是 node 的右子树
// 每个 node 右子树的 next, 就是 node next 的 左子树

/*
class Solution {
    public Node connect(Node root) {
        // 递归解法:核心是理解这个思想
        // 每个 node 左子树的 next , 就是 node 的右子树
        // 每个 node 右子树的 next, 就是 node next 的 左子树
        dfs(root,null);
        return root;
    }
    // 这里设置两个参数,一个是node,一个node的next节点
    public void dfs(Node node,Node next){
        if( node != null ){
            // 设置node的next指向
            node.next = next;
            // 递归
            dfs(node.left,node.right);
            // 这里要避免空指针异常
            dfs(node.right,node.next != null ? node.next.left : null);
        }
    }
}

226. 翻转二叉树(dfs)

/**
 * 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 TreeNode invertTree(TreeNode root) {
        if(root == null) return null;
        Swap(root,root.left,root.right);
        invertTree(root.left);
        invertTree(root.right);
        return root;
    }
    public void Swap(TreeNode root, TreeNode root1,TreeNode root2){
            // int temp = root1.val;
            // root1.val = root2.val;
            // root2.val = temp;
            TreeNode temp = root1;
            root1 = root2;
            root2 = temp;
            // 这一步是必须的,两个节点指针交换了
            // 必须修改父亲节点指向啊
            root.left = root1;
            root.right = root2;
    }
}

235. 二叉搜索树的最近公共祖先(dfs+搜索树性质)

通用解法:

/**
 * Definition for a binary tree node.
 * public class TreeNode {
 *     int val;
 *     TreeNode left;
 *     TreeNode right;
 *     TreeNode(int x) { val = x; }
 * }
 */

class Solution {
    public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) {
        /**
        分析:
        之前做过一道最近公共祖先的题,比这题难。本题该限制了树是搜索树。
        下面的解法是通用解法
         */
         if( root == null ) return null;
         if( root == p || root == q) return root;
         TreeNode left = lowestCommonAncestor(root.left,p,q);
         TreeNode right = lowestCommonAncestor(root.right,p,q);
         // 后序遍历天然具有回溯的性质
         // 左子树为空 说明两个节点都在右子树上,返回右子树即可
         if( left == null ) return right;
         // 右子树为空 说明两个节点都在左子树上,返回左子树节点即可
         if(right == null ) return left;
         return root;
    }
}

利用搜索树性质,根节点大于左子节点,小于右子节点。

class Solution {
    public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) {
        TreeNode res = root;
        while( res !=null){
            if( res.val > p.val && res.val > q.val){
                // 在左子树
                res = res.left;
            }else if(res.val < p.val && res.val < q.val){
                // 在右子树
                res = res.right;
            }else{
                break;
            }
        }
        return res;
    }
}

501. 二叉搜索树中的众数(在于读懂题目,设计众数列表)

看到二叉搜索树,那么搜索就是想到中序遍历,因为中序遍历二叉搜索树就是遍历有序数组。

class Solution {
    int prevNum = 0;
    int count = 0;
    int maxCount = 0;
    List<Integer> ans = new ArrayList<>();
    public int[] findMode(TreeNode root) {
        /**
        分析:
        看到二叉搜索树,那么搜索就是想到中序遍历,因为中序遍历二叉搜索树就是遍历有序数组。
        基本思路:中序遍历生成一个数组,然后用哈希表保存个数,遍历哈希表,时间复杂度是O(n)
        进阶思路:中序遍历的时候,更新一个众数列表,最后遍历这个众数列表即可。难点就在于设计这个众数列表
         */
         // 中序遍历
         dfs(root);
         // 遍历列表
         int[] res = new int [ans.size()];
         for(int i = 0; i < ans.size(); i++){
             res[i] = ans.get(i);
         }
         return res;

    }
    public void dfs(TreeNode root){
        if( root == null) return;
        dfs(root.left);
        update(root.val);
        dfs(root.right);
    }
    public void update(int val){
        if(val == prevNum){
            // 和上一个值一样
            count++;
        }else{
            // 不一样 设置个数为1
            count = 1;
            prevNum = val;
        }
        // 出现重复总数
        if(maxCount == count){
            ans.add(val);
        }
        if(count > maxCount){
            // 更新最大个数
            maxCount = count;
            // 清空列表
            ans.clear();
            // 加入新的宗数
            ans.add(val);
        }
    }
}

538. 把二叉搜索树转换为累加树(dfs,全局变量的设置)

/**
 * 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 {
    int curSum = 0;
    public TreeNode convertBST(TreeNode root) {
        /**
        分析:
        从测试案例中可以看到遍历方式是:右-根-左
         */
         if( root == null ) return null;
         dfs(root);
         return root;
    }
    public void dfs(TreeNode root){
        if(root == null){
            return ;
        }
        dfs(root.right);
        curSum += root.val; 
        root.val = curSum;
        dfs(root.left);

    }
}

617. 合并二叉树(dfs)

/**
 * 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 TreeNode mergeTrees(TreeNode root1, TreeNode root2) {
        if(root1 == null) return root2;
        if(root2 == null ) return root1;
        TreeNode newRoot = new TreeNode(root1.val + root2.val);
        newRoot.left = mergeTrees(root1.left,root2.left);
        newRoot.right = mergeTrees(root1.right,root2.right);
        return newRoot;
    }
   
}

701. 二叉搜索树中的插入操作(dfs)

/**
 * 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 TreeNode insertIntoBST(TreeNode root, int val) {
        // 找到插入位置,返回新建节点
        if( root == null ) return new TreeNode(val);
        if( root.val < val){
            // 递归建立右子树
            root.right =  insertIntoBST(root.right,val);
        }else{
            // 递归建立左子树
            root.left = insertIntoBST(root.left,val);
        }
        return root;

    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值