【不失业计划】二叉树常见用法及题目汇总

二叉树

1、二叉树

n(n>=0)个结点的有限集合,该集合或者为空集(称为空二叉树),或者由一个根结点和两棵互不相交的、分别称为根结点的左子树和右子树组成。

(1)满二叉树

在一棵二叉树中。如果所有分支结点都存在左子树和右子树,并且所有叶子都在同一层上,这样的二叉树称为满二叉树。
特点
1)叶子只能出现在最下一层。出现在其它层就不可能达成平衡。
2)非叶子结点的度一定是2。
3)在同样深度的二叉树中,满二叉树的结点个数最多,叶子数最多。

在这里插入图片描述

(2)完全二叉树

对一颗具有n个结点的二叉树按层编号,如果编号为i(1<=i<=n)的结点与同样深度的满二叉树中编号为i的结点在二叉树中位置完全相同,则这棵二叉树称为完全二叉树。

特点
1)叶子结点只能出现在最下层和次下层。
2)最下层的叶子结点集中在树的左部。
3)倒数第二层若存在叶子结点,一定在右部连续位置。
4)如果结点度为1,则该结点只有左孩子,即没有右子树。
5)同样结点数目的二叉树,完全二叉树深度最小。
6)满二叉树一定是完全二叉树,但反过来不一定成立。

在这里插入图片描述

(3)二叉搜索树

又称二叉查找树或二叉排序树。一棵二叉搜索树是以二叉树来组织的,可以使用一个链表数据结构来表示,其中每一个结点就是一个对象。

特点:

1)若任意结点的左子树不空,则左子树上所有结点的值均不大于它的根结点的值。

2)若任意结点的右子树不空,则右子树上所有结点的值均不小于它的根结点的值。

3)任意结点的左、右子树也分别为二叉搜索树。

在这里插入图片描述

2、二叉树遍历与递归
(1)三种遍历
  • 以根访问顺序决定是什么遍历

  • 左子树都是优先右子树

① 前序遍历:

Root -> Left -> Right 先访问根节点,再前序遍历左子树,再前序遍历右子树

/** leetcode 144 二叉树的前序遍历
* 给你二叉树的根节点 root ,返回它节点值的前序遍历。
* 输入:root = [1,null,2,3]
* 输出:[1,2,3]
*/

/**
 * 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<>();
        preTra(res,root);
        return res;
    }
    void preTra(List<Integer> res,TreeNode root){
        if(root==null)  return;
        res.add(root.val);
        preTra(res,root.left);
        preTra(res,root.right);
    }
}
② 中序遍历

Left-> Root-> Right 先中序遍历左子树,再访问根节点,再中序遍历右子树

/** leetcode 94 二叉树的中序遍历
* 给你二叉树的根节点 root ,返回它节点值的中序遍历。
* 输入:root = [1,null,2,3]
* 输出:[1,3,2]
*/

/**
 * 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> inorderTraversal(TreeNode root) {
        List<Integer> res = new ArrayList<>();
        inoTra(res,root);
        return res;
    }
    void inoTra(List<Integer> res,TreeNode root){
        if(root==null)  return;
        inoTra(res,root.left);
        res.add(root.val);
        inoTra(res,root.right);
    }
}
③ 后序遍历

Left-> Right-> Root 先后序遍历左子树,再后序遍历右子树,再访问根节点

/** leetcode 94 二叉树的后序遍历
* 给你二叉树的根节点 root ,返回它节点值的后序遍历。
* 输入:root = [1,null,2,3]
* 输出:[3,2,1]
*/

/**
 * 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) {
        List<Integer> res = new ArrayList<>();
        posTra(res,root);
        return res;
    }
    void posTra(List<Integer> res,TreeNode root){
        if(root==null)  return;
        posTra(res,root.left);
        posTra(res,root.right);
        res.add(root.val);
    }
}
(2)分治法

先分别处理局部,再合并结果

分治法模板

  • 递归返回条件
  • 分段处理
  • 合并结果
/**leetcode 110 平衡二叉树
给定一个二叉树,判断它是否是高度平衡的二叉树。
本题中,一棵高度平衡二叉树定义为:
一个二叉树每个节点 的左右两个子树的高度差的绝对值不超过 1 。

思路:分治法,左边平衡 && 右边平衡 && 左右两边高度 <= 1, 因为需要返回是否平衡及高度,要么返回两个数据,要么合并两个数据, 所以用-1 表示不平衡,>0 表示树高度(二义性:一个变量有两种含义)。
*/

/**
 * 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 boolean isBalanced(TreeNode root) {
        if(root == null){
            return true;
        }

        int d = judge(root);
        if(d>=0){
            return true;
        }
        return false;
    }
    
    public int judge(TreeNode root){
        if(root == null){
            return 0;
        }
        
        //分治
        int l = judge(root.left);
        int r = judge(root.right);
        if(l >= 0 && r >= 0 && Math.abs(l - r) <= 1) {
            return Math.max(l,r)+1;
        }else{
            return -1;
        }
    }
}
/** leetcode 124 二叉树中的最大路径和
给定一个非空二叉树,返回其最大路径和。
本题中,路径被定义为一条从树中任意节点出发,沿父节点-子节点连接,达到任意节点的序列。该路径至少包含一个节点,且不一定经过根节点。

示例 1:
输入:[1,2,3]

       1
      / \
     2   3

输出:6
示例 2:
输入:[-10,9,20,null,null,15,7]

   -10
   / \
  9  20
    /  \
   15   7

输出:42

思路:分治法,分为三种情况:左子树最大路径和最大,右子树最大路径和最大,左右子树最大加根节点最大,需要保存两个变量:一个保存子树最大路径和,一个保存左右加根节点和,然后比较这个两个变量选择最大值即可
*/

/**
 * Definition for a binary tree node.
 * public class TreeNode {
 *     int val;
 *     TreeNode left;
 *     TreeNode right;
 *     TreeNode(int x) { val = x; }
 * }
 */
class Solution {
    private int ans = Integer.MIN_VALUE;
    public int maxPathSum(TreeNode root) {
        fun(root);
        return ans;
    }

    public int fun(TreeNode root){
        if(root == null){
            return 0;
        }
        int leftNum = Math.max(0, fun(root.left));
        int rightNum = Math.max(0, fun(root.right));
        ans =  Math.max(ans, leftNum+rightNum+root.val);
        return  Math.max(leftNum,rightNum)+root.val;
    }
}
(2)DFS_深度优先

​ 从一个顶点V0开始,沿着一条路一直走到底,如果发现不能到达目标解,那就返回到上一个节点,然后从另一条路开始走到底,尽量往深处走。

/**剑指offer 55 二叉树的深度
输入一棵二叉树的根节点,求该树的深度。从根节点到叶节点依次经过的节点(含根、叶节点)形成树的一条路径,最长路径的长度为树的深度。
例:
给定二叉树 [3,9,20,null,null,15,7],

    3
   / \
  9  20
    /  \
   15   7
返回它的最大深度 3 。
*/

/**
 * Definition for a binary tree node.
 * public class TreeNode {
 *     int val;
 *     TreeNode left;
 *     TreeNode right;
 *     TreeNode(int x) { val = x; }
 * }
 */
class Solution {
    int res = 0;
    public int maxDepth(TreeNode root) {
        dfs(root,0);
        return res;
    }
    void dfs(TreeNode root,int count){
        //终止条件
        if(root==null)  return;
        
        count++;
        
        if(root.left!=null){ 
            dfs(root.left,count);
        }
        if(root.right!=null){
            dfs(root.right,count);  
        }
        res = Math.max(res,count);
    }
}

  • 查找二叉树所有路径
/** leetcode 257 二叉树的所有路径
给定一个二叉树,返回所有从根节点到叶子节点的路径。
说明: 叶子节点是指没有子节点的节点。
示例:
输入:

   1
 /   \
2     3
 \
  5
输出: ["1->2->5", "1->3"]
解释: 所有根节点到叶子节点的路径为: 1->2->5, 1->3
*/


/**
 * Definition for a binary tree node.
 * public class TreeNode {
 *     int val;
 *     TreeNode left;
 *     TreeNode right;
 *     TreeNode(int x) { val = x; }
 * }
 */
class Solution {
    List<String> res = new ArrayList<>();
    public List<String> binaryTreePaths(TreeNode root) {
        if(root==null)  return res;
        dfs(root,""+root.val,1); //分别表示二叉树,待加入res的字符串,当前结点深度
        return res;
    }

    void dfs(TreeNode root,String temp,int count){
        if(root == null)    return;
        
        if(count>1){  //当深度不在原始根节点时,字符串中添加内容
            temp = temp+"->"+root.val;
        }
        count++;
        dfs(root.left,temp,count);
        dfs(root.right,temp,count);

        if(root.left == null && root.right==null){
            res.add(temp);
        }   
    }
}
  • 二叉树中和为某一值的路径
/**剑指 Offer 34. 二叉树中和为某一值的路径
输入一棵二叉树和一个整数,打印出二叉树中节点值的和为输入整数的所有路径。从树的根节点开始往下一直到叶节点所经过的节点形成一条路径。
示例:
给定如下二叉树,以及目标和 sum = 22,

              5
             / \
            4   8
           /   / \
          11  13  4
         /  \    / \
        7    2  5   1
返回:
[
   [5,4,11,2],
   [5,8,4,5]
] */

/**
 * 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>> pathSum(TreeNode root, int sum) {
        List<List<Integer>> res = new ArrayList<>();
        if(root==null)  return res;
        dfs(root,sum,res,new ArrayList<>());
        return res;
    }
    void dfs(TreeNode root,int sum,List<List<Integer>> res,List<Integer> temp){
        if(root==null){
            if(sumFun(temp)==sum){
                res.add(new ArrayList(temp));       
            }
            return;
        }
        
        temp.add(root.val);
         if(root.left==null){
            dfs(root.right,sum,res,temp);
        }else if(root.right==null){
            dfs(root.left,sum,res,temp);

        }else{
            dfs(root.left,sum,res,temp);
            dfs(root.right,sum,res,temp);

        }
        temp.remove(temp.size()-1);

    }

    int sumFun(List<Integer> temp){
        int sum = 0;
        for(int i=0;i<temp.size();i++){
            sum+=temp.get(i);
        }
        return sum;
    }
}

(3)BFS_广度优先

搜索是从根节点开始,沿着树的宽度遍历树的节点。如果所有节点均被访问,则算法中止。

  • 从上到下打印二叉树
/** 剑指 Offer 32 - I. 从上到下打印二叉树
从上到下打印出二叉树的每个节点,同一层的节点按照从左到右的顺序打印。

例如:
给定二叉树: [3,9,20,null,null,15,7],

    3
   / \
  9  20
    /  \
   15   7

返回:
[3,9,20,15,7]

class Solution {
    public int[] levelOrder(TreeNode root) {
         if (root == null) return new int[]{};

        int[] ans = new int[1024];
        int counter = 0;
        Queue<TreeNode> queue = new LinkedList<TreeNode>();
        queue.offer(root);

        while (!queue.isEmpty()) {
            TreeNode cur = queue.poll();
            ans[counter++] = cur.val;
            if (cur.left != null) {
                queue.offer(cur.left);
            }
            if (cur.right != null) {
                queue.offer(cur.right);
            }
        }

        return Arrays.copyOf(ans, counter);
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值