leetcode刷题 二叉树

本文详细介绍了二叉树的前序、中序、后序遍历方法,并提供了递归和非递归实现代码示例。同时,还探讨了最大深度、平衡二叉树等高级主题。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

这篇博客记录 leetcode中 二叉树有关的问题

先是三大遍历

即:

前序遍历,总是先访问当前节点,再左子,最后右子

中序遍历,总是先访问左子,再当前节点,最后右子

后序遍历,总是先访问左子,再右子,最后当前节点

条件反射的记住非递归全都是用栈,后序遍历多了一个节点记录访问的过程。

每种遍历我都用递归和非递归实现了一遍,每种方式都得会才行

144Binary Tree Preorder Traversal

/**
 * Definition for a binary tree node.
 * public class TreeNode {
 *     int val;
 *     TreeNode left;
 *     TreeNode right;
 *     TreeNode(int x) { val = x; }
 * }
 */
public class Solution {
    public List<Integer> preorderTraversal(TreeNode root) {
//         迭代的方法
//         List<Integer> list = new ArrayList<Integer>() ;
//         Stack<TreeNode> stack = new Stack<TreeNode>() ;
//         if(root == null){
//             return list ;
//         }
//         stack.push(root);
//         先访问根结点,在循环之前就出栈,所以不用在循环里面判断根结点是否为空
//         while(!stack.isEmpty()){
//             TreeNode node = stack.pop() ;
//             list.add(node.val);
//             if(node.right != null){
//                 stack.push(node.right) ;
//             }
//             if(node.left != null){
//                 stack.push(node.left) ;
//             }  
//         }
//         return list ;

        
//         递归的方法
            
    //         List<Integer> list = new ArrayList<Integer>() ;
    //         traversal(root , list);
    //         return list ;             
    // }
    //         private void traversal(TreeNode root , List<Integer> list){
    //             if(root == null){
    //                 return  ;
    //         }
    //             list.add(root.val) ;
    //             traversal(root.left , list) ;
    //             traversal(root.right , list) ;
            
        //分治的方法
            List<Integer> list = new ArrayList<Integer>() ;
            if(root == null){
                return list ;
            }
//         分
            List<Integer> left = preorderTraversal(root.left);
            List<Integer> right  = preorderTraversal(root.right);
//         治
            list.add(root.val) ;
            list.addAll(left) ;
            list.addAll(right) ;
            return list ;
        
        
    
            }
           
}

94Binary Tree Inorder Traversal

/**
 * Definition for a binary tree node.
 * public class TreeNode {
 *     int val;
 *     TreeNode left;
 *     TreeNode right;
 *     TreeNode(int x) { val = x; }
 * }
 */
public class Solution {
    public List<Integer> inorderTraversal(TreeNode root) {
        List<Integer> list = new ArrayList<Integer>();
        Stack<TreeNode> stack = new Stack<TreeNode>();
        if(root ==null){
            return list ;
        }
        TreeNode cur = root ;
//         注意和先序遍历不一样,这里不能先把根结点先push,要加到while里面判断,
        while(!stack.isEmpty() || cur != null){
            while(cur != null){
                stack.push(cur) ;
                cur = cur.left ;
            }
            if(!stack.isEmpty()){
                cur = stack.pop() ;
                list.add(cur.val) ;
                cur = cur.right ;
            }
        }
        return list ;
        
        
        
        
   
//         分治法
//         List<Integer> list = new ArrayList<Integer>() ;
//         if(root == null){
//             return list ;
//         }
//         List<Integer> l = inorderTraversal(root.left) ;
//         List<Integer> r = inorderTraversal(root.right) ;
        
//         list.addAll(l);
//         list.add(root.val);
//         list.addAll(r);
//         return list ;
        
    }
}
后序遍历最难的一个一定要记清楚了多用了一个cur节点

145Binary Tree Postorder Traversal

/**
 * Definition for a binary tree node.
 * public class TreeNode {
 *     int val;
 *     TreeNode left;
 *     TreeNode right;
 *     TreeNode(int x) { val = x; }
 * }
 */
class Solution {
    public List<Integer> postorderTraversal(TreeNode root) {
//         List<Integer> list = new ArrayList<Integer>() ;
//         if(root == null){
//             return list ;
//         }
        
//         List<Integer> l = postorderTraversal(root.left);
//         List<Integer> r = postorderTraversal(root.right);
        
        
//         list.addAll(l) ;
//         list.addAll(r) ;
//         list.add(root.val) ;
//         return list ;
//         以下下思路是我百度的,我想不出来~~~~~~~
// (1)如果pre的左孩子或者右孩子是cur,那么说明遍历在往下走,按访问顺序继续,即如果有左孩子,则是左孩子进栈,否则如果有右孩子,则是右孩子进栈,如果左右孩子都没有,则说明该结点是叶子,可以直接访问并把结点出栈了。
// (2)如果反过来,cur的左孩子是pre,则说明已经在回溯往上走了,但是我们知道后序遍历要左右孩子走完才可以访问自己,所以这里如果有右孩子还需要把右孩子进栈,否则说明已经到自己了,可以访问并且出栈了。
// (3)如果cur的右孩子是pre,那么说明左右孩子都访问结束了,可以轮到自己了,访问并且出栈即可。
            List<Integer> list = new ArrayList<Integer>() ;
            Stack<TreeNode> stack = new Stack<TreeNode>() ;
            TreeNode cur = root ;
//         追逐指针
            TreeNode pre = null ;
            if(root == null){
                return list ;
            }
            stack.push(cur) ;
            while(!stack.isEmpty()){
                cur = stack.peek();
//          如果pre的左孩子或者右孩子是cur,那么说明遍历在往下走,按访问顺序继续,即如果有左孩子,则是左孩子进栈,否则如果有右孩子,则是右孩子进栈,如果左右孩子都没有,则说明该结点是叶子,可以直接访问并把结点出栈了。
                if(pre == null || pre.left == cur || pre.right == cur){
                    if(cur.left != null){
                        stack.push(cur.left);
                    }
                    else if(cur.right != null){
                        stack.push(cur.right) ;
                    }
                }
//           如果反过来,cur的左孩子是pre,则说明已经在回溯往上走了,但是我们知道后序遍历要左右孩子走完才可以访问自己,所以这里如果有右孩子还需要把右孩子进栈,否则说明已经到自己了,可以访问并且出栈了。
                else if(cur.left == pre){
                    if(cur.right != null){
                        stack.push(cur.right) ;
                    }
                }
//           如果cur的右孩子是pre,那么说明左右孩子都访问结束了,可以轮到自己了,访问并且出栈即可。      
                else{
                    list.add(cur.val);
                    stack.pop() ;
                }
                pre = cur ;
            }
            return list ;
    }
}

104Maximum Depth of Binary Tree
求二叉树的最大深度,用分治法,先求左右子树的最大深度然后再把最深的一个加一就是结果
/**
 * Definition for a binary tree node.
 * public class TreeNode {
 *     int val;
 *     TreeNode left;
 *     TreeNode right;
 *     TreeNode(int x) { val = x; }
 * }
 */
public 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 ;
    }
}

110Balanced Binary Tree 判断一个二叉树是否是平衡的,也是分治法

/**
 * Definition for a binary tree node.
 * public class TreeNode {
 *     int val;
 *     TreeNode left;
 *     TreeNode right;
 *     TreeNode(int x) { val = x; }
 * }
 */
public class Solution {
    public boolean isBalanced(TreeNode root) {
     return MaxDepth(root) != -1;
    }
    private int MaxDepth(TreeNode root){
        if(root == null){
            return 0;
        }
//         分治法分别看左右子树是否是平衡的
        int left = MaxDepth(root.left);
        int right = MaxDepth(root.right);
//         如果左右子树不平衡或者 左右子树高度差大于一,就认为是不平衡的
        if(left == -1 || right == -1 || Math.abs(left - right) > 1){
//             设不平衡时返回 -1 
            return -1;
        }
//         其余情况返回树的高度
        return Math.max(left , right) + 1;
    }
}

124Binary Tree Maximum Path Sum这道题比较难,具体的分析看我代码的zhu sh

/**
 * Definition for a binary tree node.
 * public class TreeNode {
 *     int val;
 *     TreeNode left;
 *     TreeNode right;
 *     TreeNode(int x) { val = x; }
 * }
 */
public class Solution {
//     分治法
    //因为要传递两个参数,所以要新建一个类
    private class help{
            int singlePath ;
            int maxPath;
            help(int singlePath , int maxPath){
                this.singlePath = singlePath;
                this.maxPath = maxPath;
            }
        }
    private help helper(TreeNode root){
        if(root == null){
            //递归终止条件,0表示一个点都没取到,Integer.MIN_VALUE表示一条路径都取不到;
            return new help (0 , Integer.MIN_VALUE);
        }
        //divide
        help left = helper(root.left);
        help right = helper(root.right);
        
        //conquer
//         有三种情况,一种是左边的单路路径最长,一种是右边的单路路径最长,一种是横跨左右加根节点的路径最长
        //计算最长的单路路径
        int singlePath = Math.max(left.singlePath , right.singlePath) + root.val;
        //和0比较小于零说明是负数就不要
        singlePath = Math.max(singlePath , 0);
        //计算左右子树的最长路径
        int maxPath = Math.max(left.maxPath , right.maxPath);
        //总共的最长路径和左右子树的最长路径相比较
        maxPath = Math.max(maxPath , left.singlePath + right.singlePath + root.val);
            
        return new help(singlePath , maxPath);
    }
    public int maxPathSum(TreeNode root) {
        help help = helper(root);
        return help.maxPath;
    }
}

235 Lowest Common Ancestor of a Binary Search Tree

这道题注意是二叉搜索树,应该先百度什么是二叉搜索树,利用他的性质

/**
 * Definition for a binary tree node.
 * public class TreeNode {
 *     int val;
 *     TreeNode left;
 *     TreeNode right;
 *     TreeNode(int x) { val = x; }
 * }
 */点击打开链接
public class Solution {
    public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) {
  
        if(root == null || p == null || q == null)
            return null;
//         说明在左子树
        if(root.val > p.val && root.val > q.val)
            return lowestCommonAncestor(root.left , p , q);
//         说明在右子树
        if(root.val < p.val && root.val < q.val)
            return lowestCommonAncestor(root.right , p , q);
        return root;
    }
}

236Lowest Common Ancestor of a Binary Tree
这个题是上个题的升级版,注意不能用二叉搜索树的性质!

/**
 * 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 || p == root || q == root) {
            return root;
        }

        // 查看左子树中是否有目标结点,没有为null
        TreeNode l = lowestCommonAncestor(root.left,p,q);
        // 查看右子树中是否有目标结点,没有为null
        TreeNode r = lowestCommonAncestor(root.right,p,q);

        //都不为空,说明做右子树都有目标结点,则公共祖先就是本身
        if(l!= null && r!= null) {
            return root;
        }
        // 其他情况,则要继续向下标记,显示此节点下边有目标节点
        return l != null?l:r;
    }
}
102Binary Tree Level Order Traversal基本题型bfs 用一个队列来实现

/**
 * Definition for a binary tree node.
 * public class TreeNode {
 *     int val;
 *     TreeNode left;
 *     TreeNode right;
 *     TreeNode(int x) { val = x; }
 * }
 */
public class Solution {
    public List<List<Integer>> levelOrder(TreeNode root) {
        List<List<Integer>> list = new LinkedList<List<Integer>>() ;
//         用队列来保存访问顺序
        Queue<TreeNode> queue = new LinkedList<TreeNode>() ;
        if(root == null){
            return list ;
        }
//        根节点先入队
        queue.offer(root);
//         队列不为空循环继续
        while(!queue.isEmpty()){
//             当前队列的size()就是上一层的节点数注意这是重点
            int size = queue.size() ;
//              每一层的元素存到一个队列里面
            List<Integer> levelList = new LinkedList<Integer>() ;
            for(int i = 0 ; i < size ; i ++){
                if(queue.peek().left != null){
//                     给下一层做准备
                    queue.add(queue.peek().left) ;
                }
//                 注意没有else
                if(queue.peek().right != null){
                    queue.add(queue.peek().right) ;
                }
                levelList.add(queue.poll().val) ;
            }
            list.add(levelList) ;
        }
        return list ;
    }
}


107Binary Tree Level Order Traversal II 这就是上个题的变形,将得到的队列反转就好了

/**
 * Definition for a binary tree node.
 * public class TreeNode {
 *     int val;
 *     TreeNode left;
 *     TreeNode right;
 *     TreeNode(int x) { val = x; }
 * }
 */
class Solution {
    public List<List<Integer>> levelOrderBottom(TreeNode root) {
        List<List<Integer>> list = new LinkedList<List<Integer>>() ;
        Queue<TreeNode> queue = new LinkedList<TreeNode>() ;
        if(root == null){
            return list ;
        }
        queue.add(root) ;
        while(!queue.isEmpty()){
            int size = queue.size() ;
            List<Integer> levelList = new LinkedList<Integer>() ;
            for(int i = 0 ; i < size ; i ++){
                if(queue.peek().left != null){
                queue.add(queue.peek().left) ;
            }
                if(queue.peek().right != null){
                queue.add(queue.peek().right) ;
            }
                levelList.add(queue.poll().val) ;
            }
            list.add(0 ,levelList) ;
        }
        return list ;
    }
}

103Binary Tree Zigzag Level Order Traversalbfs变形版,具体方法看注释

/**
 * Definition for a binary tree node.
 * public class TreeNode {
 *     int val;
 *     TreeNode left;
 *     TreeNode right;
 *     TreeNode(int x) { val = x; }
 * }
 */
// 主要思想就是奇数层正常的广度优先遍历 偶数层将遍历的链表先翻转再加入到list中
class Solution {
    public List<List<Integer>> zigzagLevelOrder(TreeNode root) {
        List<List<Integer>> list = new LinkedList<List<Integer>>() ;
        Queue<TreeNode> queue = new LinkedList<TreeNode>() ;
        
        if(root == null){
            return list ; 
        }
//      用来判断现在是奇数层还是偶数层 ;
        int a = 1 ;
        queue.add(root);
        while(!queue.isEmpty()){
            List<Integer> levelList = new LinkedList<Integer>() ;
            int size = queue.size() ;
            for(int i = 0 ; i < size ; i ++){
                if(queue.peek().left != null){
                    queue.add(queue.peek().left) ;
                }
                if(queue.peek().right != null){
                    queue.add(queue.peek().right) ;
                }
//              判断奇偶,奇数正常,偶数反转 ;
                if(a % 2 != 0){
                    levelList.add(queue.poll().val);
                }else{
                    levelList.add(0 , queue.poll().val) ;
                }  
            }
            a ++ ;
            list.add(levelList) ;
        }
        return list ;
    }
}

98Validate Binary Search Tree判断一个树是否是二叉搜索树,二叉搜索树的中序遍历是一个升序的list,先进行中序遍历然后,再判断是否是升序的

/**
 * Definition for a binary tree node.
 * public class TreeNode {
 *     int val;
 *     TreeNode left;
 *     TreeNode right;
 *     TreeNode(int x) { val = x; }
 * }
 */
// 二叉查找树的中序遍历应该是升序的,思路就是先进行中序遍历,在判断遍历后得到的链表是不是升序的;
public class Solution {
    public boolean isValidBST(TreeNode root) {
            List<Integer> newList = inOrder(root) ;
            int size = newList.size() ;
//         判断后一位是否大于前一位
            for(int i = 0 ; i < size - 1 ; i++){
                if(newList.get(i) >= newList.get(i + 1)){
                    return false ;
                }
            }
        return true ;
        }
//     先中序遍历
    private List inOrder(TreeNode root){
        List<Integer> list = new LinkedList<Integer>() ;
        if(root == null){
            return list ;
        }
        List<Integer> left = inOrder(root.left) ;
        List<Integer> right = inOrder(root.right) ;
        list.addAll(left) ;
        list.add(root.val) ;
        list.addAll(right) ;
        return list ; 
    }
}













评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值