Java二叉树

代码随想录一刷(2024-01-23 ~ 2024-01-26)

1.二叉树的构造

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

2.二叉树的前中后序遍历(深度优先遍历)

力扣前序遍历

力扣中序遍历

力扣后序遍历

方法一:递归法

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

        res.add(root.val);
        preorder(root.left, res);
        preorder(root.right, res);
    }
}
//中序遍历
class Solution {
    public List<Integer> inorderTraversal(TreeNode root) {
        List<Integer> res = new ArrayList<>();
        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);
    }
}
//后序遍历
class Solution {
    public List<Integer> postorderTraversal(TreeNode root) {
        List<Integer> res = new ArrayList<>();
        postorder(root, res);
        return res;
    }
    public void postorder(TreeNode root, List<Integer> res){
        if(root == null) return;

        postorder(root.left, res);
        postorder(root.right, res);
        res.add(root.val);
    }
}

方法二:迭代法

前序遍历

/**
 * 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> preorderTraversal(TreeNode root) {
        List<Integer> res = new ArrayList<>();
        if(root == null) return res;
        Stack<TreeNode> stack = new Stack<>();
        stack.push(root);
        while(!stack.isEmpty()){
            TreeNode node = stack.pop();
            res.add(node.val);
            if(node.right != null) stack.push(node.right);
            if(node.left != null) stack.push(node.left);
        }
        return res;
    }
}

中序遍历

class Solution {
    public List<Integer> inorderTraversal(TreeNode root) {
        List<Integer> res = new ArrayList<>();
        if(root == null) return res;
        Stack<TreeNode> st = new Stack<>();
        TreeNode cur = root;
        while(cur != null || !st.isEmpty()){
            if(cur != null){
                st.push(cur);
                cur = cur.left;
            }else{
                cur = st.pop();
                res.add(cur.val);
                cur = cur.right;
            }
        }
        return res;
    }
}

后序遍历

class Solution {
    public List<Integer> postorderTraversal(TreeNode root) {
        List<Integer> res = new ArrayList<>();
        if(root == null) return res;
        Stack<TreeNode> st = new Stack<>();
        st.push(root);
        while(!st.isEmpty()){
            TreeNode cur = st.pop();
            res.add(cur.val);
            if(cur.left != null) st.push(cur.left);
            if(cur.right != null) st.push(cur.right);
        }
        Collections.reverse(res);//反转数组
        return res;
    }
}

3.二叉树的层序遍历

力扣102-二叉树的层序遍历

方法一:递归法

//递归法!!!!!
class Solution {
    List<List<Integer>> res = new ArrayList<List<Integer>>();
    public void order(TreeNode node, int deep){
        if(node == null) return;//当根节点为空时结束递归
        deep ++;//元素属于第deep层,放在第deep-1个cur里;

        if(res.size() < deep){//用size和deep之间的关系限制要不要再加一层
            List<Integer> cur = new ArrayList<Integer>();//其实就是层数
            res.add(cur);
        }
        
        res.get(deep - 1).add(node.val);//选择相应的层数加进去

        order(node.left, deep);//递归左子结点
        order(node.right, deep);//递归右子结点
    }
    public List<List<Integer>> levelOrder(TreeNode root) {
        order(root, 0);
        return res;
    } 
}

方法二:利用队列来进行遍历(迭代)

ArrayList适用于频繁查询和随机访问的场景,而LinkedList适用于频繁插入、删除和位置变动较多的场景

class Solution {
    public List<List<Integer>> levelOrder(TreeNode root) {
        List<List<Integer>> res = new ArrayList<List<Integer>>();
        if(root == null) return res;
        Queue<TreeNode> q = new LinkedList<>();
        q.offer(root);//先把第一层的放进队列里面

        while(!q.isEmpty()){
            List<Integer> cur = new ArrayList<Integer>();//每次循环就建立新的一层
            int size = q.size();//用来记录每一层要放的值(也就是每次循环之后,队列里还剩的数的个数)
            while(size > 0){
                TreeNode temp = q.poll();
                cur.add(temp.val);//把数放进它所在层的cur中

                if(temp.left != null) q.offer(temp.left);//把这个数的左子节点放进队列
                if(temp.right != null) q.offer(temp.right);//这个数的右子节点放进队列
                size --;//每把一个数放进cur中,size就减1
            }
            res.add(cur);//把每一层放进答案里面
        }
        return res;
    }
}

 力扣107-二叉树的层序遍历2

在上面代码的基础上加上下面一段代码(即翻转) 

List<List<Integer>> res2 = new ArrayList<List<Integer>>();
for(int i = res.size() - 1; i >= 0; i --){
    res2.add(res.get(i));
}

力扣199-二叉树的右视图 

class Solution {
    public List<Integer> rightSideView(TreeNode root) {
        List<Integer> res = new ArrayList<Integer>();
        if(root == null) return res;
        Queue<TreeNode> q = new LinkedList<>();

        q.offer(root);
        while(!q.isEmpty()){
            //因为是一起输出来,所以不用每次都建立新的一层
            int size = q.size();
            for(int i = 0; i < size; i ++){
                TreeNode temp = q.poll();
                if(temp.left != null) q.offer(temp.left);
                if(temp.right != null) q.offer(temp.right);
                if(i == size - 1) res.add(temp.val);//只输出每层的最后一个元素就行
            }
        }
        return res;
    }
}

力扣637-二叉树的层平均值 

class Solution {
    public List<Double> averageOfLevels(TreeNode root) {
        List<Double> res = new ArrayList<>();
        if(root == null) return res;
        Queue<TreeNode> q = new LinkedList<>();

        q.offer(root);
        while(!q.isEmpty()){
            double sum = 0.0;
            int size = q.size();
            int s1 = size;
            while(size > 0){
                TreeNode temp = q.poll();
                if(temp.left != null) q.offer(temp.left);
                if(temp.right != null) q.offer(temp.right);
                sum += temp.val;
                size --;
            }
            res.add(sum / s1);//每层求出平均值加进去就行
        }
        return res;
    }
}

力扣429-N叉树的层序遍历 

class Solution {
    public List<List<Integer>> levelOrder(Node root) {
        List<List<Integer>> res = new ArrayList<List<Integer>>();
        if(root == null) return res;
        Queue<Node> q = new LinkedList<>();

        q.offer(root);
        while(!q.isEmpty()){
            List<Integer> levelres = new ArrayList<Integer>();
            int size = q.size();
            for(int i = 0; i < size; i ++){
                //这里最好用for循环,不要用while
                Node temp = q.poll();
                levelres.add(temp.val);
                List<Node> children = temp.children;//就只有这里变了,一个节点有多个孩子
                if(children == null || children.size() == 0) continue;
                for(Node child : children){
                    if(child != null) q.offer(child);
                }
            }
            res.add(levelres);
        }
        return res;
    }
}

力扣515-在每个树行中找最大值 

class Solution {
    public List<Integer> largestValues(TreeNode root) {
        List<Integer> res = new ArrayList<Integer>();
        if(root == null) return res;
        Queue<TreeNode> q = new LinkedList<>();

        q.offer(root);
        while(!q.isEmpty()){
            int size = q.size();
            int max = Integer.MIN_VALUE;//因为要求最大值,所以先把int类型的最小取值数赋给max
            for(int i = 0; i < size; i ++){
                TreeNode temp = q.poll();
                max = temp.val > max ? temp.val : max;
                if(temp.left != null) q.offer(temp.left);
                if(temp.right != null) q.offer(temp.right);
            }
            res.add(max);
        }
        return res;
    }
}

力扣116-填充每个结点的下一个右侧结点指针 

class Solution {
    public Node connect(Node root) {
        Queue<Node> q = new LinkedList<>();
        if(root == null) return root;
        q.offer(root);
        while(!q.isEmpty()){
            int size = q.size();
            Node cur = q.poll();//这里的cur都是每一层的第一个
            if(cur.left != null) q.offer(cur.left);//要先把左右孩子放进队列,后面才能建立联系
            if(cur.right != null) q.offer(cur.right);
            for(int i = 1; i < size; i ++)//这里只循环size-1次(假如这一层有n个元素,那么只要建立n-1个联系就好了)
            {
                Node next = q.poll();
                if(next.left != null) q.offer(next.left);//把左右孩子放进队列,后面才能找到下一层元素
                if(next.right != null) q.offer(next.right);
                cur.next = next;
                cur = next;
            }
        }
        return root;
    }
}

​​​​​​力扣117-填充每个结点的下一个右侧结点指针2 

class Solution {
    public Node connect(Node root) {
        Queue<Node> q = new LinkedList<>();
        if(root != null) q.offer(root);
        while(!q.isEmpty()){
            int size = q.size();
            Node cur = null;
            Node next = null;
            for(int i = 0; i < size; i ++){
                if(i == 0){
                    cur = q.poll();
                    next = cur;
                }else{
                    next = q.poll();
                    cur.next = next;
                    cur = next;
                }
                if(cur.left != null) q.offer(cur.left);
                if(cur.right != null) q.offer(cur.right);
            }
            cur.next = null;//这一层的最后一个数指向null
        }
        return root;
    }
}

4.翻转二叉树 

力扣226-翻转二叉树 

class Solution {
    public TreeNode invertTree(TreeNode root) {
        if(root == null) return root;
        swap(root);//只需要在遍历二叉树的基础上,加上左右孩子节点交换就行
        invertTree(root.left);
        invertTree(root.right);
        return root;
    }
    public void swap(TreeNode root){
        TreeNode t = root.left;
        root.left = root.right;
        root.right = t;
    }
}

5.对称二叉树 

力扣101-对称二叉树 

class Solution {
    public boolean isSymmetric(TreeNode root) {
        return compare(root.left, root.right);
    }
    public boolean compare(TreeNode left, TreeNode right){
        //先把终止情况先列出来,一共有五种(要用后序遍历)
        if(left == null && right != null) return false;//左孩子为空,右孩子不为空
        if(left != null && right == null) return false;//右孩子为空,左孩子不为空
        if(left != null && right != null && left.val != right.val) return false;//都不为空,但是值不相等
        if(left == null && right == null) return true;//左右都为空

        //还有一种是左右孩子的值都相等,就继续往下遍历
        boolean outside = compare(left.left, right.right);//判断外侧孩子是否对称
        boolean inside = compare(left.right, right.left);//判断内侧孩子是否对称
        return inside && outside;//把结果返回父节点
    }
}

力扣100-相同的树 

class Solution {
    public boolean isSameTree(TreeNode p, TreeNode q) {
        return compare(p, q);
    }
    public boolean compare(TreeNode p, TreeNode q){
        if(p != null && q == null) return false;
        if(p == null && q != null) return false;
        if(p != null && q != null && p.val != q.val) return false;
        if(p == null && q == null) return true;

        boolean left = compare(p.left, q.left);//和101对称二叉树相同,把左孩子和左孩子比较
        boolean right = compare(p.right, q.right);//右孩子和右孩子比较
        return left && right;
    }
}

力扣572-另一棵树的子树 

class Solution {
    public boolean isSubtree(TreeNode root, TreeNode subRoot) {
        if(subRoot == null) return true;//subRoot为null一定都是true
        if(root == null) return false;//root为null一定都是false
        //1.递归左子树判断是否相等 
        //2.递归右子树,判断是否相等 
        //3.就根节点开始比较 
        //只要这三种情况有一种成立,就返回true
        return isSubtree(root.right, subRoot) || isSubtree(root.left, subRoot) || compare(root, subRoot);
    }
    public boolean compare(TreeNode p, TreeNode q){
        //下面的代码和前面几题都一样,都是比较一棵树是否相等
        if(p == null && q == null) return true;
        if(p != null && q == null) return false;
        if(p == null && q != null) return false;
        if(p != null && q != null && p.val != q.val) return false;

        boolean left = compare(p.left, q.left);
        boolean right = compare(p.right, q.right);
        return left && right;
    }
}

6.二叉树的最大、最小深度 

最大深度 

104. 二叉树的最大深度 - 力扣(LeetCode)

方法一:迭代法(层序遍历)

class Solution {
    public int maxDepth(TreeNode root) {
        Queue<TreeNode> q = new LinkedList<>();
        int h = 0;
        if(root == null) return h;
        q.offer(root);
        while(!q.isEmpty()){
            int size = q.size();
            while(size > 0){
                TreeNode cur = q.poll();
                if(cur.left != null) q.offer(cur.left);
                if(cur.right != null) q.offer(cur.right);
                size --;
            }
            h ++;//每循环一层,深度加1
        }
        return h;
    }
}

 方法二:递归法 

class Solution {
    public int maxDepth(TreeNode root) {
        if(root == null) return 0;//知道root为空,就返回0
        //找出左右子树最大深度的一边 深度再加1
        return Math.max(maxDepth(root.left), maxDepth(root.right)) + 1;
    }
}

 力扣559-N叉树的最大深度 

方法一:层序遍历

class Solution {
    public int maxDepth(Node root) {
        Queue<Node> q = new LinkedList<>();
        int h = 0;
        if(root == null) return h;
        q.offer(root);
        while(!q.isEmpty()){
            h ++;
            int size = q.size();
            for(int i = 0; i < size; i ++){
                Node cur = q.poll();
                List<Node> children = cur.children;
                if(children == null || children.size() == 0) continue;
                for(Node child : children) 
                    if(child != null) q.offer(child);
            }
        }
        return h;
    }
}

方法二:递归 

class Solution {
    public int maxDepth(Node root) {
        if(root == null) return 0;
        int depth = 0;
        if(root.children != null){
            for(Node child : root.children){
                depth = Math.max(depth, maxDepth(child));//循环每个孩子节点,找到最大那个
            }
        }
        return depth + 1;//后序遍历(返回给父节点)
    }
}

最小深度 

111. 二叉树的最小深度 - 力扣(LeetCode) 

方法一:层序遍历(迭代法)

class Solution {
    public int minDepth(TreeNode root) {
        Queue<TreeNode> q = new LinkedList<>();
        int h = 0;
        if(root == null) return h;
        q.offer(root);
        while(!q.isEmpty()){
            h ++;
            int size = q.size();
            while(size > 0){
                TreeNode cur = q.poll();
                if(cur.left == null && cur.right == null) return h;//如果当前节点的左右孩子都为空,那就直接返回最小深度
                if(cur.left != null) q.offer(cur.left);
                if(cur.right != null) q.offer(cur.right);
                size --;
            }
        }
        return h;
    }
}

方法二:递归法 

class Solution {
    public int minDepth(TreeNode root) {
        if(root == null) return 0;
        int leftdepth = minDepth(root.left);
        int rightdepth = minDepth(root.right);
        if(root.left == null) return rightdepth + 1;//左子树为空,右子树不为空,最小深度是1+右子树的深度
        if(root.right == null) return leftdepth + 1;//右子树为空,左子树不为空,最小深度是1+左子树的深度

        return Math.min(leftdepth, rightdepth) + 1;//左右子树都不为空,返回左右子树深度最小值+1 
    }
}

7.完全二叉树的节点个数 

222. 完全二叉树的节点个数 - 力扣(LeetCode)

方法一:递归法

class Solution {
    public int countNodes(TreeNode root) {
        if(root == null) return 0;
        return countNodes(root.left) + countNodes(root.right) + 1; //自身的结点1 加上左右子树的节点总数
    }
}

 方法二:层序遍历(迭代法)

class Solution {
    public int countNodes(TreeNode root) {
        if(root == null) return 0;
        Queue<TreeNode> q = new LinkedList<>();
        q.offer(root);
        int result = 0;//用来记录点的个数
        while(!q.isEmpty()){
            int size = q.size();
            while(size > 0){
                TreeNode temp = q.poll();
                result ++;
                if(temp.left != null) q.offer(temp.left);
                if(temp.right != null) q.offer(temp.right);
                size --;
            }
        }
        return result;
    }
}

方法三:利用完全二叉树本身的性质 

class Solution {
    public int countNodes(TreeNode root) {
        if(root == null) return 0;
        TreeNode left = root.left;//先把左右子树分开
        TreeNode right = root.right;
        int leftdepth = 0, rightdepth = 0;
        while(left != null){
            left = left.left;//沿最左侧不断往下
            leftdepth ++;
        }
        while(right != null){
            right = right.right;//沿最右侧不断往下
            rightdepth ++;
        }
        //如果左右两侧深度相等,那么说明这是满二叉树
        //满二叉树的结点数为:2^depth - 1
        if(rightdepth == leftdepth) return (2 << leftdepth) - 1;// 2<<1 等同于 2^2
        return countNodes(root.left) + countNodes(root.right) + 1;//左子树的结点数+右子树的结点数+自身的1
    }
}

二叉树节点的深度与高度(概念)

深度:从根节点到该节点的最长简单路径边的条数

高度:从该节点到叶子节点的最长简单路径边的条数

求深度用前序遍历:是一直向下遍历的,不需要向上返回结果

求高度用后序遍历:因为是要从左右子节点开始算起,返回父节点,最终返回给根节点(左右中)

8.平衡二叉树的判断 

110. 平衡二叉树 - 力扣(LeetCode)

递归法(使用后序遍历,将左右子树的结果返回给父节点)

class Solution {
    public boolean isBalanced(TreeNode root) {
        //返回值为0和树的高度 都说明是平衡二叉树
        //返回值为-1,说明不是平衡二叉树
        return getHeight(root) != -1;
    }
    public int getHeight(TreeNode root){
        if(root == null) return 0;//节点为空直接返回0,这里不单指根节点
        //判断左子树是不是平衡二叉树
        //如果是的话,就求出左子树的高度,并返回
        //左子树就不是平衡二叉树了,就直接返回-1
        int leftHeight = getHeight(root.left);
        if(leftHeight == -1) return -1;
        //求出右子树的高度
        //或者右子树就不是平衡二叉树了
        int rightHeight = getHeight(root.right);
        if(rightHeight == -1) return -1;
        //左右子树的高度差超过1,就不是平衡二叉树,返回-1
        if(Math.abs(leftHeight - rightHeight) > 1) return -1;
        //求出树的高度
        return Math.max(leftHeight, rightHeight) + 1;
    }
}

 9.二叉树与路径有关的题目

257. 二叉树的所有路径 - 力扣(LeetCode)

使用前序遍历(父节点指向孩子节点,才能把路径输出)

方法一:递归法

1. toString()  Java toString() 方法 | 菜鸟教程 (runoob.com)

2. append()   JAVA中的append()方法_append java-CSDN博客

3.StringBuilder() Java StringBuffer 和 StringBuilder 类 | 菜鸟教程 (runoob.com) 

class Solution {
    List<String> result = new ArrayList<>();
    public List<String> binaryTreePaths(TreeNode root) {
        path(root, "");
        return result;
    }
    public void path(TreeNode root, String s){
        if(root == null) return;//根节点为空直接返回
        if(root.left == null && root.right == null)//当节点没有左右孩子,说明到了叶子节点
        {
            //直接把前面的路径字符串加上当前叶子节点就行
            result.add(new StringBuilder(s).append(root.val).toString());
            return;
        }
        String temp = new StringBuilder(s).append(root.val).append("->").toString();
        //把前面的公共路径temp传进函数,然后再分开左右结点进行遍历
        path(root.left, temp);//遍历左边结点
        path(root.right, temp);//遍历右边结点
    }
}

 方法二:迭代法

1.Object 类     Java Object 类 | 菜鸟教程 (runoob.com)

class Solution {
    public List<String> binaryTreePaths(TreeNode root) {
        List<String> result = new ArrayList<>();
        if(root == null) return result;
        Stack<Object> st = new Stack<>();
        st.push(root);
        st.push(root.val + "");
        while(!st.isEmpty()){
            String path = (String)st.pop();//取出节点路径(根节点到当前节点)
            TreeNode temp = (TreeNode)st.pop();//取出当前节点
            //如果找到叶子结点,那就直接把路径放进结果里面
            if(temp.left == null && temp.right == null)   result.add(path);
            //先进右再进左,才能先出左后出右
            if(temp.right != null)//右子节点不为空
            {
                st.push(temp.right);//把现在的节点放进栈中
                st.push(path + "->" + temp.right.val);//路径加上当前节点
            }
            if(temp.left != null)//左子节点不为空
            {
                st.push(temp.left);//把现在的节点放进栈中保存起来
                st.push(path + "->" + temp.left.val);//当前节点放进路径里面
            }
        }
        return result;
    }
}

112. 路径总和 - 力扣(LeetCode) 

方法一:迭代法

class Solution {
    public boolean hasPathSum(TreeNode root, int targetSum) {
        if(root == null) return false;
        Stack<Object> st = new Stack<>();
        st.push(root);
        st.push(root.val);
        while(!st.isEmpty()){
            int sum = (int)st.pop();
            TreeNode temp = (TreeNode)st.pop();
            if(temp.left == null && temp.right == null && sum == targetSum) return true;
            if(temp.right != null){
                st.push(temp.right);
                st.push(sum + temp.right.val);
            }
            if(temp.left != null){
                st.push(temp.left);
                st.push(sum + temp.left.val);
            }
        }
        return false;
    }
}

方法二:递归法

class Solution {
    public boolean hasPathSum(TreeNode root, int targetSum) {
        if(root == null) return false;//根节点为空,返回false
        if(root.left == null && root.right == null) return root.val == targetSum;//叶子节点判断
        //只要左右有一条成立就行,总目标值要减去当前节点值(这是属于已经走过的路)在进行递归
        return hasPathSum(root.left, targetSum - root.val) || hasPathSum(root.right, targetSum - root.val);
    }
}

 

113. 路径总和 II - 力扣(LeetCode)

 1.removeLast   Java.util.LinkedList.removeLast() 方法 (w3schools.cn)

 2.result.add(new LinkedList<>(path))力扣77题关于result.add(new LinkedList<>(path))的解释_result.add(new arraylist<>(path))-CSDN博客

class Solution {
    List<List<Integer>> result;
    List<Integer> path;
    public List<List<Integer>> pathSum(TreeNode root, int targetSum) {
        result = new LinkedList<>();
        path = new LinkedList<>();
        sum(root, targetSum);
        return result;
    }
    public void sum(TreeNode root, int targetSum){
        if(root == null) return;
        path.add(root.val);
        targetSum -= root.val;
        if(root.left == null && root.right == null && targetSum == 0)
            result.add(new LinkedList<>(path));
        sum(root.left, targetSum);
        sum(root.right, targetSum);
        path.removeLast();//回溯(会重复多次)
    }
}

 

10.左叶子之和

​​​​​​ 
404. 左叶子之和 - 力扣(LeetCode)

方法一:递归法

class Solution {
    public int sumOfLeftLeaves(TreeNode root) {
        if(root == null) return 0;
        int leftValue = sumOfLeftLeaves(root.left);//当前节点的左孩子的左叶子结点
        int rightValue = sumOfLeftLeaves(root.right);//当前节点的右孩子的左叶子节点
        int midValue = 0;//当前节点的左叶子节点
        if(root.left != null && root.left.left == null && root.left.right == null) midValue = root.left.val;
        return midValue + rightValue + leftValue;
    }
}

方法二:迭代法(前序遍历)

class Solution {
    public int sumOfLeftLeaves(TreeNode root) {
        if(root == null) return 0;
        Stack<TreeNode> st = new Stack<>();
        st.push(root);//把根节点放进栈中
        int result = 0;
        while(!st.isEmpty()){
            TreeNode temp = st.pop();//每次取出一个结点进行遍历(这样就可以遍历完这棵树了)
            //还是那个判断条件
            if(temp.left != null && temp.left.left == null && temp.left.right == null){
                result += temp.left.val;
            }
            if(temp.left != null) st.push(temp.left);//把父节点的左孩子放进栈中(如果左孩子不为空)
            if(temp.right != null) st.push(temp.right);
        }
        return result;
    }
}

方法三:层序遍历(迭代法)

class Solution {
    public int sumOfLeftLeaves(TreeNode root) {
        int result = 0;
        if(root == null) return result;
        Queue<TreeNode> q = new LinkedList<>();
        q.offer(root);
        while(!q.isEmpty()){
            int size = q.size();
            while(size > 0){
                TreeNode temp = q.poll();//遍历了每个节点
                if(temp.left != null){
                    q.offer(temp.left);//把当前节点的左节点加进队列,如果不为空的话
                    if(temp.left.left == null && temp.left.right == null){
                        result += temp.left.val;
                    }
                }
                if(temp.right != null) q.offer(temp.right);//右节点加进队列
                size --;
            }
        }
        return result;
    }
}

 

11.树左下角的值

513. 找树左下角的值 - 力扣(LeetCode)

适合用层序遍历

class Solution {
    public int findBottomLeftValue(TreeNode root) {
        //题目限定了至少有一个结点,所以不用判断root为空的情况
        Queue<TreeNode> q = new LinkedList<>();
        q.offer(root);
        int res = 0;
        while(!q.isEmpty()){
            int size = q.size();
            for(int i = 0; i < size; i ++){
                TreeNode temp = q.poll();
                if(i == 0) res = temp.val;//i=0是每层的最左边,i会不断的被覆盖,直到是最后一层的最左边
                if(temp.left != null) q.offer(temp.left);
                if(temp.right != null) q.offer(temp.right);
            }
        }
        return res;
    }
}

12.从中序与(前、后)序遍历序列构造二叉树

106. 从中序与后序遍历序列构造二叉树 - 力扣(LeetCode)

class Solution {
    Map<Integer, Integer> map;
    public TreeNode buildTree(int[] inorder, int[] postorder) {
        map = new HashMap<>();//保存中序序列中数值以及其相对应的位置
        for(int i = 0; i < inorder.length; i ++){
            map.put(inorder[i], i);
        }
        //所有的范围都要统一原则:满足左闭右开
        return findNode(inorder, 0, inorder.length, postorder, 0, postorder.length);
    }
    public TreeNode findNode(int[] inorder, int inFirst, int inEnd, int[] postorder, int postFirst, int postEnd){
        if(inEnd <= inFirst || postEnd <= postFirst) return null;//不满足左闭右开,没有元素,就返回
        int rootIndex = map.get(postorder[postEnd - 1]);//从后序序列中找到根节点,求出它在中序序列中的位置
        TreeNode root = new TreeNode(inorder[rootIndex]);//建立根节点
        int leftLength = rootIndex - inFirst;//求出左区间的长度
        //求左孩子
        root.left = findNode(inorder, inFirst, rootIndex, postorder, postFirst, postFirst + leftLength);
        //求右孩子
        root.right = findNode(inorder, rootIndex + 1, inEnd, postorder, postFirst + leftLength, postEnd - 1);
        return root;
    }
}

105. 从前序与中序遍历序列构造二叉树 - 力扣(LeetCode) 

class Solution {
    Map<Integer,Integer> map;
    public TreeNode buildTree(int[] preorder, int[] inorder) {
        map = new HashMap<>();
        for(int i = 0; i < inorder.length; i ++){
            map.put(inorder[i], i);
        }
        return findNode(inorder, 0, inorder.length, preorder, 0, preorder.length);
    }
    public TreeNode findNode(int[] inorder, int inFirst, int inEnd, int[] preorder, int preFirst, int preEnd){
        if(inEnd <= inFirst || preEnd <= preFirst) return null;
        int nodeIndex = map.get(preorder[preFirst]);
        TreeNode root = new TreeNode(inorder[nodeIndex]);
        int leftLength = nodeIndex - inFirst;
        root.left = findNode(inorder, inFirst, nodeIndex, preorder, preFirst + 1, preFirst + leftLength + 1);
        root.right = findNode(inorder, nodeIndex + 1, inEnd, preorder, preFirst + leftLength + 1, preEnd);
        return root;
    }
}

相关题目 

654. 最大二叉树 - 力扣(LeetCode) 

class Solution {
    public TreeNode constructMaximumBinaryTree(int[] nums) {
        return constructMaximumBinaryTree1(nums, 0, nums.length);
    }
    public TreeNode constructMaximumBinaryTree1(int[] nums, int first, int end){
        if(first >= end) return null;//为空,或者不满足左闭右空原则
        if(first + 1 == end) return new TreeNode(nums[first]);//只有一个元素
        
        int maxIndex = first;//先把它赋给第一个
        int max = nums[maxIndex];
        for(int i = first + 1; i < end; i ++)//循环比较可以从第二个元素开始
        {
            if(max < nums[i]){
                maxIndex = i;
                max = nums[i];
            }
        }
        TreeNode root = new TreeNode(max);
        //根据maxIndex划分左右区间
        root.left = constructMaximumBinaryTree1(nums, first, maxIndex);
        root.right = constructMaximumBinaryTree1(nums, maxIndex + 1, end);
        return root;
    }
}

13.合并二叉树

 617. 合并二叉树 - 力扣(LeetCode)

 方法一:递归法

class Solution {
    public TreeNode mergeTrees(TreeNode root1, TreeNode root2) {
        if(root1 == null) return root2;//如果树1结点为空,直接返回树2
        if(root2 == null) return root1;//同上
        //只有两树的结点都不为空,才有以下的情况发生
        root1.val += root2.val;
        root1.left = mergeTrees(root1.left, root2.left);
        root1.right = mergeTrees(root1.right, root2.right);
        return root1;
    }
}

方法二:使用队列迭代

class Solution {
    public TreeNode mergeTrees(TreeNode root1, TreeNode root2) {
        if(root1 == null) return root2;
        if(root2 == null) return root1;
        Queue<TreeNode> q = new LinkedList<>();
        q.offer(root1);
        q.offer(root2);
        while(!q.isEmpty()){
            TreeNode node1 = q.poll();//队列先进先出
            TreeNode node2 = q.poll();
            //此时两个节点一定不为空
            node1.val += node2.val;
            //两数的左节点不为空,加入队列
            if(node1.left != null && node2.left != null){
                q.offer(node1.left);
                q.offer(node2.left);
            }
            //两数的右节点不为空,加入队列
            if(node1.right != null && node2.right != null){
                q.offer(node1.right);
                q.offer(node2.right);
            }
            //树1的左节点为空,直接把树2的左节点赋值给它
            if(node1.left == null && node2.left != null){
                node1.left = node2.left;
            }
            //树1的右节点为空,直接把树2的右节点赋值给它
            if(node1.right == null && node2.right != null){
                node1.right = node2.right;
            }
            //还有一种情况是树1有,树2为空,但由于返回的是树1,所以这种情况不用考虑(已经在那里了)
        }
        return root1;
    }
}


14.二叉搜索树的搜索  

 700. 二叉搜索树中的搜索 - 力扣(LeetCode)

方法一:递归法 

class Solution {
    public TreeNode searchBST(TreeNode root, int val) {
        if(root == null || root.val == val) return root;
        //利用二叉搜索树的特点,小的在左边,大的在右边
        if(root.val > val) return searchBST(root.left, val);
        else return searchBST(root.right, val);
    }
}

 方法二:迭代法

class Solution {
    public TreeNode searchBST(TreeNode root, int val) {
        while(root != null){
            if(root.val > val) root = root.left;
            else if(root.val < val) root = root.right;
            else return root;
        }
        return null;
    }
}

15.验证二叉搜索树

98. 验证二叉搜索树 - 力扣(LeetCode)

方法一:递归法

class Solution {
    public boolean isValidBST(TreeNode root) {
        //这里不能用Integer.MAX_VALUE,会报错
        return check(root, Long.MAX_VALUE, Long.MIN_VALUE);
    }
    public boolean check(TreeNode root, long upper, long lower){
        if(root == null) return true;
        if(root.val <= lower || root.val >= upper) return false;
        return check(root.left, root.val, lower) && check(root.right, upper, root.val);
    }
}

 方法二:迭代法(利用二叉搜索树与中序遍历相似的特点)

class Solution {
    private long temp = Long.MIN_VALUE;//记得这个temp要在函数外面定义!!!而且要定义成long类型的,int会报错
    public boolean isValidBST(TreeNode root) {
        //根据二叉搜索树的定义可以想到中序遍历(它们的大小关系是左<中<右)
        if(root == null) return true;
        if(!isValidBST(root.left)) return false;
        if(temp >= root.val) return false;//
        temp = root.val;
        return isValidBST(root.right);
    }
}

 

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

 

 530. 二叉搜索树的最小绝对差 - 力扣(LeetCode)

方法一:递归法 

class Solution {
    TreeNode temp;
    int result = Integer.MAX_VALUE;
    public int getMinimumDifference(TreeNode root) {
        if(root == null) return 0;
        minGet(root);
        return result;
    }
    public void minGet(TreeNode root){
        if(root == null) return;
        minGet(root.left);
        if(temp != null) result = Math.min(result, Math.abs(root.val - temp.val));
        temp = root;//用来记录上一个节点
        minGet(root.right);
    }
}

方法二:迭代法(中序遍历) 

class Solution {
    //中序遍历
    public int getMinimumDifference(TreeNode root) {
        if(root == null) return 0;
        int result = Integer.MAX_VALUE;
        Stack<TreeNode> st = new Stack<>();
        TreeNode cur = root;
        TreeNode pre = null;//用来保存上一个节点
        while(cur != null || !st.isEmpty()){
            if(cur != null){
                st.push(cur);//将访问的节点放进栈里面
                cur = cur.left;//一直递归到最左
            }else{
                cur = st.pop();
                if(pre != null) result = Math.min(result, Math.abs(cur.val - pre.val));//中
                pre = cur;
                cur = cur.right;//右
            }
        }
        return result;
    }
}

 

 17.二叉搜索树中的众数

501. 二叉搜索树中的众数 - 力扣(LeetCode)

递归法(利用中序遍历)

class Solution {
    List<Integer> result = new ArrayList<>();
    TreeNode pre;//记录上一个节点
    int maxcount;//记录最大数量
    int count;//记录每个数的数量
    public int[] findMode(TreeNode root) {
        maxcount = 0;
        count = 0;
        pre = null;//给其赋初始值
        findMode1(root);
        int[] res = new int[result.size()];//因为返回类型是int的数组
        for(int i = 0; i < result.size(); i ++){
            res[i] = result.get(i);//注意这里get函数的用法,里面要有i
        }
        return res;
    }
    public void findMode1(TreeNode root){
        //根据二叉搜索树的特点(中序遍历)
        if(root == null) return;
        findMode1(root.left);//左
        if(pre == null || pre.val != root.val){
            count = 1;//如果和上一个数不一样,就重新赋值为1(包括pre结点为空的情况)
        }else{
            count ++;//如果一样,数量就加1
        }
        if(count > maxcount){
            maxcount = count;//说明更可能的众数出现了,要重新赋最大值
            result.clear();//把结果清空
            result.add(root.val);//把最新可能的众数加进去
        }else if(count == maxcount){
            result.add(root.val);//如果数量相同,就说明可能有多个众数,只需要把当前的数加入结果即可
        }
        pre = root;//保存上一个结点
        findMode1(root.right);//右
    }
}

 

18.二叉树、二叉搜索树的最近公共祖先

236. 二叉树的最近公共祖先 - 力扣(LeetCode) 

class Solution {
    public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) {
        if(root == null || 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 null;//左右都为空
        else if(left != null && right == null) return left;//找到一个(左边)
        else if(right != null && left == null) return right;//找到一个(右边)
        else return root;//左右都找到了
    }
}

 

 235. 二叉搜索树的最近公共祖先 - 力扣(LeetCode)

方法一:递归法 

class Solution {
    public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) {
        if(root.val < q.val && root.val < p.val) return lowestCommonAncestor(root.right, p, q);//比qp都小,在右边
        else if(root.val > q.val && root.val > p.val) return lowestCommonAncestor(root.left, p, q);//比qp都大,在左边
        else return root;//如果pq在root的一左一右,那么root一定是最近公共祖先
    }
}

方法二:迭代法

class Solution {
    public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) {
        while(true){
            if(root.val < p.val && root.val < q.val) root = root.right;
            else if(root.val > p.val && root.val > q.val) root = root.left;
            else break;
        }
        return root;
    }
}

 

19.二叉搜索树的基本操作(插入、删除)

701. 二叉搜索树中的插入操作 - 力扣(LeetCode) 

方法一:递归法

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 if(root.val > val) root.left = insertIntoBST(root.left, val);

        return root;
    }
}

 方法二:迭代法

class Solution {
    public TreeNode insertIntoBST(TreeNode root, int val) {
        if(root == null) return new TreeNode(val);

        TreeNode pre = root;//保存父节点,才能找到结点,进行插入的操作
        TreeNode cur = root;
        while(cur != null){
            pre = cur;
            if(cur.val > val) cur = cur.left;
            else if(cur.val < val) cur = cur.right;
        }
        if(pre.val > val) pre.left = new TreeNode(val);
        else if (pre.val < val) pre.right = new TreeNode(val);
        return root;
    }
}

450. 删除二叉搜索树中的节点 - 力扣(LeetCode)

class Solution {
    public TreeNode deleteNode(TreeNode root, int key) {
        if(root == null) return root;
        if(root.val == key)//找到删除点
        {
            if(root.left == null) return root.right;//包含第二和第三种情况
            else if(root.right == null) return root.left;//第四种情况
            else{//第五种情况(删除点左右都不为空)
                TreeNode cur = root.right;//把删除点的右子节点存下来
                while(cur.left != null) cur = cur.left;//递归找到右子节点的最左的那个点(即最小的点)
                cur.left = root.left;//把删除点的左孩子结点放进右子节点的最左的那个点
                return root.right;//返回右子节点
            }
        }
        if(root.val > key) root.left = deleteNode(root.left, key);//递归查找删除点
        if(root.val < key) root.right = deleteNode(root.right, key);
        return root;
    }
}

 

 20.修剪二叉搜索树

669. 修剪二叉搜索树 - 力扣(LeetCode)

 

class Solution {
    public TreeNode trimBST(TreeNode root, int low, int high) {
        if(root == null) return root;//返回空值

        if(root.val > high) return trimBST(root.left, low, high);//砍右大只
        if(root.val < low) return trimBST(root.right, low, high);//砍左大只
        //root在[low, high]范围内
        root.left = trimBST(root.left, low, high);
        root.right = trimBST(root.right, low, high);
        return root;
    }
}

 

21.将有序数组转换为(高度平衡)二叉搜索树 

108. 将有序数组转换为二叉搜索树 - 力扣(LeetCode)

方法一:左闭右闭 

class Solution {
    public TreeNode sortedArrayToBST(int[] nums) {
        return transform(nums, 0, nums.length - 1);
    }
    public TreeNode transform(int[] nums, int left, int right){
        //坚持左闭右闭原则
        if(left > right) return null;//当数组为空时,返回null
        //求出中心值
        int mid = left + ((right - left) >> 1);
        TreeNode root = new TreeNode(nums[mid]);//建立根节点
        root.left = transform(nums, left, mid - 1);//循环建立左右节点
        root.right = transform(nums, mid + 1, right);
        return root;
    }
}

方法二:左闭右开

class Solution {
    public TreeNode sortedArrayToBST(int[] nums) {
        return transform(nums, 0, nums.length);
    }
    public TreeNode transform(int[] nums, int left, int right){
        //全部坚持左闭右开原则
        if(left >= right) return null;
        if(right - left == 1) return new TreeNode(nums[left]);
        int mid = left + ((right - left) >> 1);
        TreeNode root = new TreeNode(nums[mid]);
        root.left = transform(nums, left, mid);
        root.right = transform(nums, mid + 1, right);
        return root;
    }
}

 

 22.把二叉搜索树转换为累加树

 

538. 把二叉搜索树转换为累加树 - 力扣(LeetCode)

class Solution {
    int sum;//定义变量,让他在函数里面可以用
    public TreeNode convertBST(TreeNode root) {
        sum = 0;
        adding(root);
        return root; 
    }
    public void adding(TreeNode root){
        if(root == null) return;
        //反向中序遍历(右中左)
        adding(root.right);
        sum += root.val;//把前面的值相加,并用sum保存下来
        root.val = sum;//把sum的值赋给结点的值
        adding(root.left);
    }
}

 

  • 49
    点赞
  • 31
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值