[算法系列]递归应用——二叉树(1):二叉树遍历详解解+LeetCode经典题目+模板总结

本文是递归算法系列文的第7篇,依然沿着递归的脉络,介绍了常常运用递归处理问题的一个典型数据结构——二叉树。分析总结了LeetCode中的相关习题在解法上的思路和模板。

本文内容如下:

  • 树的前、中、后序、层次遍历的递归和非递归写法
  • LeetCode上树的问题分类(基本遍历、路径、计数、加和、深宽、构造、BST等)
  • 两种遍历为思想的问题(判定、比较结点或子树 以及 路径[ 和 ]、累计
  • 【小结】在解决树的遍历相关问题时,我们是如何使用基本遍历方法,进行递归设计的?

由于树的相关问题题目较多,本文介绍第一部分,其余部分后续更新。(又挖了一个坑)

0.LeetCode中二叉树定义

class TreeNode {
   
    int val;
    TreeNode left;
    TreeNode right;
    TreeNode(int x) {
    val = x; }
}

1.四种遍历(递归+非递归)

1.1递归遍历

LC144前序

    List<Integer> res = new ArrayList<>();
    public List<Integer> preorderTraversal(TreeNode root) {
   
        if(root == null) return res;

        res.add(root.val);
        preorderTraversal(root.left);
        preorderTraversal(root.right);
        return res;
    }

LC94中序

    List<Integer> res = new ArrayList<>();
    public List<Integer> inorderTraversal(TreeNode root) {
   
        if(root == null)    return res;
        
        inorderTraversal(root.left);
        res.add(root.val);
        inorderTraversal(root.right);    
        return res;
    }

LC145后序

    List<Integer> res = new ArrayList<>();
    public List<Integer> postorderTraversal(TreeNode root) {
   
        if(root == null) return res;

        postorderTraversal(root.left);
        postorderTraversal(root.right);
        res.add(root.val);
        return res;
    }

1.2非递归遍历

前序

    public List<Integer> preorderTraversal(TreeNode root) {
   
        List<Integer> res = new ArrayList<>();
        if(root == null) return res;

        Deque<TreeNode> stack = new ArrayDeque<>();
        TreeNode p = root;

        while(!stack.isEmpty() || p != null){
    
            while(p!= null){
   	//一口气走到左下最后一个,一边走一边入栈、同时加入结果集
                stack.push(p);          
                res.add(p.val);      
                p = p.left;
            }    
        
            p = stack.pop().right;	//逐个往上、然后遍历右子树
        }
        return res;
    }

注:前序还有一种写法:这种写法具有结构对称美哦~后序就知道了

  • 根不空时,根入栈
  • 当栈非空时:
    • 根出栈,加入res。
    • 若右子树非空,右子树入栈
    • 若左子树非空,左子树入栈
    public List<Integer> preorderTraversal(TreeNode root) {
           
		List<Integer> res = new ArrayList<>();        
        if(root == null) return res;

        Deque<TreeNode> stack = new ArrayDeque<>();
        TreeNode p = root;
        stack.push(p);				//根节点入栈
        while(!stack.isEmpty()){
   	//当根节点不空时,出栈一个根节点,然后加入res中
            p = stack.pop();
            res.add(p.val);
            if(p.right != null)                //加入右子树入栈
                stack.push(p.right);
            if(p.left != null)				//左子树入栈
                stack.push(p.left);
        }
        return res;
    }        

中序

    public List<Integer> inorderTraversal(TreeNode root) {
   
        List<Integer> res = new ArrayList<>();    
        if(root == null)    return res;
        
        Deque<TreeNode> stack = new ArrayDeque<>();
        TreeNode p = root;

        while(!stack.isEmpty() || p != null){
    //一口气走到左下角一边走,一边入栈,
            while(p != null){
   				//但是是在出栈后才加到结果集
                stack.push(p);
                p = p.left;
            }

            p = stack.pop();
            res.add(p.val);
            p = p.right;
        }
        return res;
    }

后序

后序遍历使用了一个小技巧:

  • 后序遍历是右 =》左 =》 根, 那么我们可以先按照根 =》左 =》右(前序)进行遍历,然后将得到的结果进行翻转
    public List<Integer> postorderTraversal(TreeNode root) {
   
        List<Integer> res = new ArrayList<>();        
        if(root == null) return res;

        Deque<TreeNode> stack = new ArrayDeque<>();
        // Deque<TreeNode> temp_res = new ArrayDeque<>();
        TreeNode p = root;
        stack.push(p);
        while(!stack.isEmpty()){
   
            p = stack.pop();
            res.add(p.val);
            if(p.left != null)
                stack.push(p.left);
            if(p.right != null)                
                stack.push(p.right);
        }	
        Collections.reverse(res); //将结果翻转,这一步也可以用栈
        return res;

    }

1.3层次遍历

以LC102为例:输入二叉树数组,输出层次遍历结果,并且每一层为一个list,整体为二维list

https://leetcode-cn.com/problems/binary-tree-level-order-traversal/

    public List<List<Integer>> levelOrder(TreeNode root) {
   
        List<List<Integer>> res = new ArrayList<>();
        
        if(root == null)    
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值