LeetCode算法之--二叉树系列

简介: 很多伙伴大学的时候就学过二叉树的数据结构以及相关遍历的算法(没有学过的伙伴可以先百度学习了解一下二叉树的数据结构知识)最简单的如:前序遍历、中序遍历、后序遍历。而树这种数据结构跟其他的数据结构不太一样,稍微复杂而且抽象在解题的时候最好手画草图,把抽象的结构形象化可以提高理解度加快解题。二叉树也是面试算法的常见题型,通常程序会自定义树节点,需要我们实现如找出深度、遍历等。即使我们记得树的前中后序遍历顺序,但是要用代码来实现它却并非易事,它的难度体现在抽象、如何选择合适的数据结构等。

01前言


很多伙伴大学的时候就学过二叉树的数据结构以及相关遍历的算法(没有学过的伙伴可以先百度学习了解一下二叉树的数据结构知识)最简单的如:前序遍历、中序遍历、后序遍历。而树这种数据结构跟其他的数据结构不太一样,稍微复杂而且抽象在解题的时候最好手画草图,把抽象的结构形象化可以提高理解度加快解题。二叉树也是面试算法的常见题型,通常程序会自定义树节点,需要我们实现如找出深度、遍历等。即使我们记得树的前中后序遍历顺序,但是要用代码来实现它却并非易事,它的难度体现在抽象、如何选择合适的数据结构等。


02二叉树的最大深度


104. 二叉树的最大深度

给定一个二叉树,找出其最大深度。

二叉树的深度为根节点到最远叶子节点的最长路径上的节点数。

说明: 叶子节点是指没有子节点的节点。

示例:

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

   3

  / \

 9  20

   /  \

  15   7

返回它的最大深度 3 。

解法一】深度优先:新建一个result集合用于保存并返回结果集合,边界条件为root为null,则返回result,递归方法开始传入root和levle为0层,依次递增层数并新建结果集合里的子集list,结果集合中添加该节点的值val,并递归遍历该节点的左子树和右子树,直至递归遍历完该二叉树的所有节点,返回的result结果集合就是所求。


class Solution {   List<List<Integer>> result = new ArrayList<List<Integer>>();   public List<List<Integer>> levelOrder(TreeNode root) {     If(root == null){       return result ;     }     dfs(root,0);     return result;   }   public void dfs(TreeNode root,int level){     //递归终止条件     If(root  == null){        return ;     }      If( result.size == level){        result.add(New ArrayList<Integer>());     }     result.get(level).add(root.val);     dfs(root.right,level+1);     dfs(root.right,level+1);   }}

解法二】广度优先:新建一个result集合用于保存和返回结果集合,边界条件当root为空,则直接返回结果集。建队列queue保存root根节点,按照每一层左、右子树的顺序,一次访问二叉树的节点,遍历每一层的节点时用一个list集合把该层的所有节点从左到右顺序保存起来,遍历完每一层把list集合添加到结果集合中,遍历完所有层,result结果集合就是要求的答案。


class Solution {   public List<List<Integer>> levelOrder(TreeNode root) {     List<List<Integer>> result = new ArrayList<List<Integer>>();     If(root == null){       return result ;     }     Queue<TreeNode> queue = new LinkedList<TreeNode>();     queue.offer(root);     While(!queue.isEmpty()){       Int size = queue.size();       List<Integer> list = new ArrayList<Integer>();      While(size >0){         TreeNode node = queue.poll();         list .add(node.val);         If(node.left != null){           queue.offer(node.left);         }         If(node.right != null){         queue.offer(node.right);         }         size --;       }       result.add(list);      }    return result ;  }}


03二叉树的遍历


94. 二叉树的中序遍历

给定一个二叉树的根节点 root ,返回 它的 中序 遍历

示例 1:

dec037c541a70aa258358a39fcb8fb69_640_wx_fmt=jpeg&wxfrom=5&wx_lazy=1&wx_co=1.jpg

输入:root = [1,null,2,3]输出:[1,3,2]示例 2:

输入:root = []输出:[]示例 3:

输入:root = [1]输出:[1]提示:

树中节点数目在范围 [0, 100] 内-100 <= Node.val <= 100进阶: 递归算法很简单,你可以通过迭代算法完成吗?

解法一】迭代解决:新建一个List集合用以存放结果返回集合,新建一个Deque双端队列用作遍历二叉树出入栈使用,当root或stack不为空时,遍历二叉树,一直遍历到左子树为空时,从栈弹出节点并把弹出节点的值存入栈中,指针指向弹出节点的右子树节点,继续遍历访问弹出节点右子树节点是否为空,重复该步骤直至遍历完该二叉树为止。


class Solution {    public List<Integer> inorderTraversal(TreeNode root) {        List<Integer> dataList = new ArrayList<Integer>();        Deque<TreeNode> stack = new LinkedList<TreeNode>();        While(root != null || !stack.isEmpty()){          If(root!= null){            stack.push(root);            root = root.left;          }else{            root = stack.pop();            dataList.add(root.val);            root = root.right;         }       }       return dataList ;   }}

解法二】递归:递归的解法很简单,递归循环左节点和右节点,递归的终止条件是当root为空时返回。


class Solution {    public List<Integer> inorderTraversal(TreeNode root) {        List<Integer> dataList = new ArrayList<Integer>();        Inorder(root,dataList );        return dataList ;    }    public void inorder(TreeNode root,List<Integer> dataList){      If(root == null){        return;      }      inorder(root.left,dataList);      dataList.add(root.val);      inorder(root.right,dataList);    }}

二叉树的前序遍历

迭代解决】前序遍历的出入栈顺序是:先根节点入栈,根节点出栈,再右节点入栈、左节点入栈,左节点出栈、右节点入栈;如此往复循环直至遍历完整颗二叉树,在每一次出栈时保存节点的值放入list链表,最后得到的list结果集合就是所求结果。


class Solution {    public List<Integer> inorderTraversal(TreeNode root) {        List<Integer> dataList = new ArrayList<Integer>();        Deque<TreeNode> stack = new LinkedList<TreeNode>();        stack.push(root);         While( !stack.isEmpty()){          root = stack.pop();          dataList.add(root.val);          //先压入右节点,弹出顺序刚好相反          If(root.right != null){            stack.push(root.right );          }          //再压入左节点,弹出顺序刚好相反         If(root.left!= null){           stack.push(root.left);         }       }     return dataList ;  }}

后序遍历】后序遍历的顺序是:左节点-->右节点-->根  而出栈和入栈的顺序则刚好相反,这题的关键是需要用两个栈结构来解答,一个栈用来遍历,另一个栈用来存储,遍历完第一个栈后,第二个栈出栈遍历的结构就是后续遍历。


class Solution {    public List<Integer> inorderTraversal(TreeNode root) {        List<Integer> dataList = new ArrayList<Integer>();        //第一个栈用来遍历二叉树        Deque<TreeNode> stack1 = new LinkedList<TreeNode>();        stack1.push(root);        //第二个栈用来存放节点最终遍历出栈的顺序就是所要求结果        Deque<TreeNode> stack2 = new LinkedList<TreeNode>();        While(!stack1.isEmpty()){          root = stack1.pop();          stack2.push(root.val);           If(root.left != null){            stack1.push(root.left);          }          If(root.right != null){            stack1.push(root.right);          }        }        while(!stack2.isEmpty()){          dataList.add(stack2.pop());        }     }}


04总结


关于二叉树的解法,常见为深度优先遍历和广度优先遍历,深度优先一般选用递归解法,如求二叉树的深度、层序遍历(节点从左到右顺序)、中序遍历、反转二叉树、对称二叉树等,广度优先采用Queue队列、Deque栈的数据结构来求解,一层一层的遍历按照要求实现具体解法,广度优先也称为迭代解法。

相关文章
|
10天前
|
算法
分享一些提高二叉树遍历算法效率的代码示例
这只是简单的示例代码,实际应用中可能还需要根据具体需求进行更多的优化和处理。你可以根据自己的需求对代码进行修改和扩展。
|
13天前
|
存储 缓存 算法
如何提高二叉树遍历算法的效率?
选择合适的遍历算法,如按层次遍历树时使用广度优先搜索(BFS),中序遍历二叉搜索树以获得有序序列。优化数据结构,如使用线索二叉树减少空指针判断,自定义节点类增加辅助信息。利用递归与非递归的特点,避免栈溢出问题。多线程并行遍历提高速度,注意线程安全。缓存中间结果,避免重复计算。预先计算并存储信息,提高遍历效率。综合运用这些方法,提高二叉树遍历算法的效率。
35 5
|
13天前
|
存储 算法 Java
leetcode算法题-有效的括号(简单)
【11月更文挑战第5天】本文介绍了 LeetCode 上“有效的括号”这道题的解法。题目要求判断一个只包含括号字符的字符串是否有效。有效字符串需满足左括号必须用相同类型的右括号闭合,并且左括号必须以正确的顺序闭合。解题思路是使用栈数据结构,遍历字符串时将左括号压入栈中,遇到右括号时检查栈顶元素是否匹配。最后根据栈是否为空来判断字符串中的括号是否有效。示例代码包括 Python 和 Java 版本。
|
16天前
|
机器学习/深度学习 JSON 算法
二叉树遍历算法的应用场景有哪些?
【10月更文挑战第29天】二叉树遍历算法作为一种基础而重要的算法,在许多领域都有着不可或缺的应用,它为解决各种复杂的问题提供了有效的手段和思路。随着计算机科学的不断发展,二叉树遍历算法也在不断地被优化和扩展,以适应新的应用场景和需求。
24 0
|
1月前
|
算法
每日一道算法题(Leetcode 20)
每日一道算法题(Leetcode 20)
24 2
|
1月前
【LeetCode 31】104.二叉树的最大深度
【LeetCode 31】104.二叉树的最大深度
19 2
|
1月前
【LeetCode 29】226.反转二叉树
【LeetCode 29】226.反转二叉树
16 2
|
1月前
【LeetCode 28】102.二叉树的层序遍历
【LeetCode 28】102.二叉树的层序遍历
15 2
|
1月前
|
存储 算法 关系型数据库
数据结构与算法学习二一:多路查找树、二叉树与B树、2-3树、B+树、B*树。(本章为了解基本知识即可,不做代码学习)
这篇文章主要介绍了多路查找树的基本概念,包括二叉树的局限性、多叉树的优化、B树及其变体(如2-3树、B+树、B*树)的特点和应用,旨在帮助读者理解这些数据结构在文件系统和数据库系统中的重要性和效率。
21 0
数据结构与算法学习二一:多路查找树、二叉树与B树、2-3树、B+树、B*树。(本章为了解基本知识即可,不做代码学习)
|
1月前
|
存储 算法 搜索推荐
数据结构与算法学习十七:顺序储存二叉树、线索化二叉树
这篇文章主要介绍了顺序存储二叉树和线索化二叉树的概念、特点、实现方式以及应用场景。
25 0
数据结构与算法学习十七:顺序储存二叉树、线索化二叉树