07-二叉树类


二叉树理论基础篇

二叉树的题目分类

就是6种题型,4种二叉树的,6种二叉搜索书的
在这里插入图片描述

二叉树的种类

  • 满二叉树
    如果一棵二叉树只有度为0的结点和度为2的结点,并且度为0的结点在同一层上,则这棵二叉树为满二叉树
    若深度为k,则2^k-1个节点
    在这里插入图片描述
  • 完全二叉树
    在完全二叉树中,除了最底层节点可能没填满外,其余每层节点数都达到最大值并且最下面一层的节点都集中在该层最左边的若干位置。若最底层为第 h 层,则该层包含 1~ 2^(h-1) 个节点
    在这里插入图片描述
    优先级队列其实是一个堆,堆就是一棵完全二叉树,同时保证父子节点的顺序关系
  • 二叉搜索树
    二叉搜索树是有数值的了,二叉搜索树是一个有序树
    定义如下:
  • 若它的左子树不空,则左子树上所有结点的值均小于它的根结点的值;
  • 若它的右子树不空,则右子树上所有结点的值均大于它的根结点的值;
  • 它的左、右子树也分别为二叉排序树
    在这里插入图片描述
  • 平衡二叉搜索树
    平衡二叉搜索树:又被称为AVL(Adelson-Velsky and Landis)树,且具有以下性质:它是一棵空树或它的左右两个子树的高度差的绝对值不超过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;
  	}
}

题目

二叉树的递归遍历

递归方法论:
在这里插入图片描述
以下以前序遍历为例:
在这里插入图片描述
熟练的记住递归法的方法论,在递归的路上越走越稳!!!

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 {
    public List<Integer> preorderTraversal(TreeNode root) {
        ArrayList<Integer> Arr = new ArrayList<Integer>();
        Traversal(root,Arr);
        return Arr;
    }

        // 递归三要素
        // 确定递归函数的参数和返回值
        void Traversal(TreeNode root,ArrayList<Integer> Arr){
            // 确定递归的结束条件
            if(root == null)  return;

            // 确定单层递归逻辑
            Arr.add(root.val);
            Traversal(root.left,Arr);
            Traversal(root.right,Arr);
        
        }
 
}

145. 二叉树的后序遍历


/**
 * 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> postorderTraversal(TreeNode root) {
        ArrayList<Integer> Arr = new ArrayList<Integer>();
        Traversal(root,Arr);
        return Arr;
    }

        // 递归三要素
        // 确定递归函数的参数和返回值
        void Traversal(TreeNode root,ArrayList<Integer> Arr){
            // 确定递归的结束条件
            if(root == null)  return;

            // 确定单层递归逻辑           
            Traversal(root.left,Arr);
            Traversal(root.right,Arr);
            Arr.add(root.val);
        
        }
 
}

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) {
        ArrayList<Integer> Arr = new ArrayList<Integer>();
        Traversal(root,Arr);
        return Arr;
    }

        // 递归三要素
        // 确定递归函数的参数和返回值
        void Traversal(TreeNode root,ArrayList<Integer> Arr){
            // 确定递归的结束条件
            if(root == null)  return;

            // 确定单层递归逻辑           
            Traversal(root.left,Arr);
            Arr.add(root.val);
            Traversal(root.right,Arr);       
        }
 
}

二叉树的迭代遍历

为什么可以用迭代法(非递归的方式)来实现二叉树的前后中序遍历呢?
递归的实现就是:每一次递归调用都会把函数的局部变量、参数值和返回地址等压入调用栈中,然后递归返回的时候,从栈顶弹出上一次递归的各项参数,所以这就是递归为什么可以返回上一层位置的原因

前序遍历(迭代法)

前序遍历是中左右,每次先处理的是中间节点,那么**先将根节点放入栈中,然后将右孩子加入栈,再加入左孩子**

在这里插入图片描述

// 迭代法

class Solution {
    // 前序遍历顺序   中左右   入栈顺序:中--左----右
    public List<Integer> preorderTraversal(TreeNode root) {
        List<Integer> result = new ArrayList<Integer>();
        if(root==null) return result;

        Stack<TreeNode> stack = new Stack<>();
        stack.push(root);
        while(!stack.isEmpty()){
            TreeNode node = stack.pop();
            result.add(node.val);
            if(node.right!=null) stack.push(node.right);
            if(node.left!=null) stack.push(node.left);

        }
        return result;
        }
}

中序遍历(迭代法)

在这里插入图片描述

处理顺序和访问顺序是不一致的

方法:在使用迭代法写中序遍历,就需要借用指针的遍历来帮助访问节点,栈则用来处理节点上的元素

// 迭代法

class Solution {
    public List<Integer> inorderTraversal(TreeNode root) {
        List<Integer> result = new ArrayList<Integer>();
        if(root==null) return result;

        Stack<TreeNode> stack = new Stack<>();
        TreeNode cur = root;

        while(cur!=null||!stack.isEmpty()){
            if(cur!=null){
                stack.push(cur);
                cur=cur.left;
            }else{
                cur=stack.pop();
                result.add(cur.val);
                cur=cur.right;
            }
        }
        return result;         
        } 
}

后序遍历(迭代法)

在这里插入图片描述

// 后序遍历顺序 左-右-中 入栈顺序:中-左-右 出栈顺序:中-右-左, 最后翻转结果
class Solution {
    public List<Integer> postorderTraversal(TreeNode root) {
        List<Integer> result = new ArrayList<>();
        if (root == null){
            return result;
        }
        Stack<TreeNode> stack = new Stack<>();
        stack.push(root);
        while (!stack.isEmpty()){
            TreeNode node = stack.pop();
            result.add(node.val);
            if (node.left != null){
                stack.push(node.left);
            }
            if (node.right != null){
                stack.push(node.right);
            }
        }
        Collections.reverse(result);
        return result;
    }
}

二叉树层序遍历

102. 二叉树的层序遍历

给你二叉树的根节点 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<List<Integer>> levelOrder(TreeNode root) {
        List<List<Integer>> res = new ArrayList<>();
        if(root==null) return res;

        Queue<TreeNode> que = new LinkedList<>();

        que.add(root);

        while(!que.isEmpty()){
            List<Integer> arr = new ArrayList<>();
            int len =que.size();

            while(len>0){
                 TreeNode tre = que.poll();
                 arr.add(tre.val);

                 if(tre.left!=null) que.add(tre.left);
                 if(tre.right!=null) que.add(tre.right);

                 len--;
            }
            res.add(arr);
        }

        return res;
    
    }

}

学习:先把该建的数据结构,先建好,里面的循环画图,一步一步模拟实现

107. 二叉树的层序遍历 II

给你二叉树的根节点 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<List<Integer>> levelOrderBottom(TreeNode root) {
        List<List<Integer>> res = new ArrayList<>();
        if(root == null) return res;

        Queue<TreeNode> que = new LinkedList<>();
        que.add(root);

        while(!que.isEmpty()){
            List<Integer> arr = new ArrayList<>();
            int len = que.size();

            while(len>0){
                TreeNode tre = que.poll();
                arr.add(tre.val);
                
                if(tre.left!=null) que.add(tre.left);

                if(tre.right!=null) que.add(tre.right);
                
                len--;
            }
            res.add(arr);
        }   

        List<List<Integer>> res2 = new ArrayList<>();

        for(int i = res.size()-1;i>=0;i--){
            res2.add(res.get(i));
            
        }  
        return res2;
    }
}

学习:思路是挺好想的,但是操作时出现了弱智错误是:先将右支放进了队列,然后又放的左支

199. 二叉树的右视图

此题就两个思路,思路1:在往数组里加的时候,确定是不是len=1,如果等于1,则加进去,不等于1,不加
思路2:先求出二维数组,然后求每个数组的最后一个

637.二叉树的层平均值

此题实际上和上一题类似,思路1:就是在如何加入数组的时候进行平均操作;
思路2:就是就是先求出二维数组,然后再求每个数组的平均值

用思路2左,做了1个半小时,才做出出来,遇到了好多弱智错误:
每一次都需要新建一维数组,每一次都需要,往外弹,这些语句应该放在那个循环内,需要重视
再就是每次循环完需要将平均值av调成0,不然把以前的数也加上了
最后要注意,root能不能为null,白和傻逼一样,直接判空
要学会调试,很多问题已调试就出来了

这样做时间复杂度8%特别低,效果不是很好

用思路1做,做了接近15分钟吧,出现的问题是:将len作为了求平均数的个数,导致数组li里面全是NAN,需要自己信息新增一个count进行计数,然后让他作为被除数
再就是要保证平均数为实数,所以需要将其强转,或者让一个类型成为实数类型,避免了强转

时间复杂度达到95%,这个方法效果好很多,而且也避免了新建很多动态数组

429. N 叉树的层序遍历

在这里插入图片描述

/*
// Definition for a Node.
class Node {
    public int val;
    public List<Node> children;

    public Node() {}

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

    public Node(int _val, List<Node> _children) {
        val = _val;
        children = _children;
    }
};

此题肯定是根据N叉树的定义做的,这样也不用判断左右树,直接用Children的子类,如果子类不等于空则进行加入到数组,应该是这样

此题大约做了20分钟,实际上改的就是如何往队列中加指针的问题,先求tre的孩子集合,先判断集合有没有问题,如果没有,就进行遍历求各个孩子,如果孩子没问题,就加进队列,就是这样的一个逻辑吧
在这里插入图片描述
集合的判断实际上有一个就行!!!

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

在这里插入图片描述
思路1:还是最简单的方法,就是求出二位数组,然后再求各一维数组的最大值,但此方法不是好方法

思路2:就是在往一维数组加元素时,需要和以前的判断,如果大就替换掉他,一直替换到最后一个,那就是最大的

思路1:做出来了,大约做了24分钟左右,出现的问题主要就是求最大值,设置最小值的API有点忘了,试了试试出来了,再就是出现的些弱智错误,都是每次报错后,根据报错的信息调对的
时间复杂度比较低,才9.05%

思路2:哎,真菜,什么错也出,调了接近30分钟,才挑出来,用的思路1的代码,结果每次都创建一个一维数组,产生了错误,研究了10几分钟,也没看出哪里错,这是奇葩,再就是当len=0的时候,才需要将max加入到arr中,而不是len =1

时间复杂度也不是很高,78%

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

在这里插入图片描述
思路:
队列弹出值,值的指针指向队列的顶部

做了20分钟,没做出来,上面想的思路,不对,要保证len-1大于0才行,因为已经弹出1个元素,此时len为进行减1,需要在减1之后,队列中还有元素,才行!
为什么返回node而不是root呢?
node是最后一个元素,而root是第一个元素,后面连接着一大串

117.填充每个节点的下一个右侧节点指针II

与上一题的区别是非完美二叉树
在这里插入图片描述

104.二叉树的最大深度

在这里插入图片描述

  1. 思路: 先用层序遍历求二维数组,再求二维数组的大小,就是深度
  2. 思路: 记录一个深度数为0,len 不是大于0时,深度数 + 1
  3. 采用深度遍历应该也可以

111.二叉树的最小深度

在这里插入图片描述
思路: 当一节点的左右子树都为空时,返回当前深度,没有都为空的情况,则返回正常深度

226. 翻转二叉树

在这里插入图片描述
1.思路: 递归法: 到左节点,到右节点,然后进行交换即可【前后遍历】
2. 思路 层序遍历 直接得到二维数组,然后在进行一维数组的反转,并放进一维数组中
3. 思路: 不用队列,放进栈中应该也不错

101. 对称二叉树

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值