【LeetCode】二叉树的遍历

递归的思想:

简化问题,不要去细想,

遇到了一个点是,只有非null的才可以调用val,否则会报错。所以要先讨论为null时候的情况。

一、二叉树的中序遍历

按照访问左子树——根节点——右子树的方式遍历这棵树,而在访问左子树或者右子树的时候我们按照同样的方式遍历,直到遍历完整棵树。

1、递归

定义 inorder(root) 表示当前遍历到 root 节点的答案,那么按照定义,我们只要递归调用 inorder(root.left) 来遍历 root 节点的左子树,然后将 root 节点的值加入答案,再递归调用inorder(root.right) 来遍历 root 节点的右子树即可,递归终止的条件为碰到空节点。

/**
 * 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> ans = new ArrayList<Integer>();
        inorder(root,ans);
        return ans;
    }
    public void inorder(TreeNode root,List<Integer> ans) {

        if(root == null) return ;
        inorder(root.left,ans);
        ans.add(root.val);
        inorder(root.right,ans);



    }
}

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> inorderTraversal(TreeNode root) {

        List<Integer> res = new ArrayList<Integer>();
        Deque<TreeNode> stk = new LinkedList<TreeNode>();

        while (root !=null || !stk.isEmpty()){
            while (root!=null){
                stk.push(root);
                root = root.left;

            }
            root = stk.pop();
            res.add(root.val);
            root=root.right;


        }
        return res;

    }

}

3、Morris 中序遍历

二、二叉树的层序遍历

1、广度优先搜索

思路:

他整了一个Queue接口(先进先出)下的linkedlist(有序),命名为Que。如果Que不为空,就先看Que有多少个,然后拿出来放到tmp列表中,每拿出一个,就把这个的左右子叶放到Que里继续排队。这个新的不会在这一次循环中被放入到tmp中,因为已经提前得到了Que刚开始有多少个,所以他只会提取这些个原本存在在Que里面的数据,并把这些数据的左右子叶重新放到Que里继续排队。

在Que中的操作循环完一遍以后,把tmp放入到ret中。tmp每次都是新创的,不用清零。

只要Que里面还有东西,就说明还能继续放,就继续循环。

/**
 * 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<List<Integer>>();
        if(root == null){
            return res;
        }
        Queue<TreeNode> queue = new LinkedList<TreeNode>();
        queue.offer(root);
        while(!queue.isEmpty()){

            List<Integer> tmp = new ArrayList<Integer>();
            int n = queue.size();
            for(int i = 0; i < n ; i++){
                TreeNode node = queue.poll();
                tmp.add(node.val);
                if(node.left != null ){
                    queue.offer(node.left);
                }
                if(node.right != null ){
                    queue.offer(node.right);
                }
                
            }
            res.add(tmp);

        }
        return  res;


        
    }
}

注意区分:

条件含义适用场景
queue.isEmpty()检查队列是否没有元素​(队列已初始化但为空)判断队列内容是否处理完毕(如 BFS 遍历结束)
queue != null检查队列对象是否未被初始化(引用为 null防止空指针异常(如初始化前验证对象存在性)

补充:Queue<> 

在Java中,Queue<> 是一个接口(Interface)​,它定义了一种先进先出(FIFO, First-In-First-Out)​的数据结构。它并不是一个具体的“结构”,而是规范了队列应有的行为和操作。要理解它的本质,需要从以下几个方面入手:

队列的核心特性

  1. 先进先出(FIFO)​:最先插入的元素最先被移除。
  2. 基本操作
    • 入队(Enqueue)​:将元素添加到队列末尾。
    • 出队(Dequeue)​:移除队列头部的元素。
    • 查看队首(Peek)​:获取但不移除队列头部的元素。

Queue<>的核心方法

方法行为返回特殊值(return null/false
插入元素将元素添加到队列末尾offer(e)
移除元素移除并返回队列头部的元素poll()
查看队首元素返回队列头部的元素(不移除)peek()

三、有序数组转换为平衡二叉搜索树

给你一个整数数组 nums ,其中元素已经按 升序 排列,请你将其转换为一棵 平衡 二叉搜索树。

思路:

数组是从小到大有序的,只有每次都选中间的数作为root,深度差就可以不超过1,即可以平衡。root的左右就分成两部分再去递归。所以需要有nums,还需要有每次的序号 !

常用:参数包括左右指针的方法重点理解!!!

class Solution {
    public TreeNode sortedArrayToBST(int[] nums) {
        return helper(nums, 0, nums.length - 1);
    }

    public TreeNode helper(int[] nums, int left, int right) {
        if (left > right) {
            return null;
        }

        // 总是选择中间位置左边的数字作为根节点
        int mid = (left + right) / 2;

        TreeNode root = new TreeNode(nums[mid]);
        root.left = helper(nums, left, mid - 1);
        root.right = helper(nums, mid + 1, right);
        return root;
    }
}

四、 二叉树中的最大路径和




重点掌握:利用全局变量,直接利用这一遍的递归,就已经可以通过全局变量得到了原本需要再嵌套一层递归的结果。

天才啊

全局变量是我们最终想得到的最大值

首先能够考虑到,好像涉及到两个递归:

(1)选定一个root后,max为大于0的最大的左子树+大于0的最大的右子树。但大于0的最大的左子树为root.left的最大的左子树或者右子树;大于0的最大的右子树为root.right的最大的左子树或者右子树。

(2)root的选定轮流到每一个node。

最开始我的思路是


利用全局变量的存在,把两个递归简化成一个递归。

在选定了一个root后,需要递归得到root.left和root.right的最大支线,所以find函数里面return的要是root.val+max(root.left的最大支线,root.right的最大支线)。

max直接每次max(max,root.val+l+r)即可,直接利用全局变量,在每一次调用find函数时,root.val+l+r就相当于以这个root为根,也就包括了所有的node作为根的情况。


class Solution {
    int max = Integer.MIN_VALUE;
    public int maxPathSum(TreeNode root) {
        
        find(root);
        return max;
    }
    public int find(TreeNode root) {
        if (root == null) {
            return 0;
        }
        int l = Math.max(find(root.left),0);
        int r = Math.max(find(root.right),0);
        
        int tmp = root.val + l + r;

        max = Math.max(max,tmp);

        return root.val + Math.max(l,r);
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值