leetcode二叉树题目总结

题目链接:https://leetcode-cn.com/leetbook/detail/data-structure-binary-tree/

前序遍历(NLR)

    1. public List<Integer> preorderTraversal(TreeNode root) {
    2. List<Integer> res = new ArrayList<>();
    3. preOrder(root, res);
    4. return res;
    5. }

    6. public void preOrder(TreeNode root, List<Integer> res) {
    7. if (root == null)
    8. return;
    9. res.add(root.val);
    10. preOrder(root.left, res);
    11. preOrder(root.right, res);
    12. }

中序遍历(LNR)

    1. inOrder(root.left, res);
    2. res.add(root.val);
    3. inOrder(root.right, res);

后序遍历( LRN )

    1. postOrder(root.left, res);
      postOrder(root.right, res);
      res.add(root.val);

层次遍历

  1.   3
      / \
    9 20
      / \
      15   7
    结果
    [
    [3],
    [9,20],
    [15,7]
    ]

关键代码

  1. public List<List<Integer>> levelOrder(TreeNode root) {
  2. // 空树判断
  3. if(root == null) return result;
  4. // 返回的结果
  5. List<List<Integer>> result = new ArrayList<>();
  6. // 队列
  7. Queue<TreeNode> queue = new LinkedList<>();
  8. // 根节点入队
  9. queue.add(root);
  10. // 队列不为空则循环
  11. while(queue.size()>0){
  12. // 内层节点序列
  13. List<Integer> temp = new ArrayList<>();
  14. // 遍历队列,把当前层的元素从队列取出来,将下一层放入队列
  15. for(int i=0;i<size;i++){
  16. // 当前节点放入结果数组
  17. TreeNode cur = queue.poll();
  18. temp.add(cur);
  19. // 左节点入队
  20. if(cur.left){
  21. queue.add(cur.left);
  22. }
  23. // 右节点入队
  24. if(cur.right){
  25. queue.add(cur.right)
  26. }
  27. }
  28. result.add(temp);
  29. }
  30. return result;
  31. }

二叉树最大深度

递归解决:

  • 递归出口 当前节点 == null 返回0

  • 递归逻辑 Math.max(maxDept(root.left) +1, maxDepth(root.right) +1)

  1. public int maxDepth(TreeNode root) {
  2. if(root == null) return 0;
  3. return Math.max(maxDepth(root.left)+1, maxDepth(root.right)+1);
  4. }

对称二叉树

递归法:

递归出口: 两个节点同时为空 return true 有一个为空 return false

递归逻辑: 返回当前节点值是否相等 && 递归节点1的左节点和节点2的右节点 && 递归节点2的右节点和节点1的左节点

  1. class Solution {
  2. public boolean isSymmetric(TreeNode root) {
  3. return isMirror(root, root);
  4. }
  5. public boolean isMirror(TreeNode t1, TreeNode t2) {
  6. if (t1 == null && t2 == null) return true;
  7. if (t1 == null || t2 == null) return false;
  8. return (t1.val == t2.val)
  9. && isMirror(t1.left, t2.right)
  10. && isMirror(t1.right, t2.left);
  11. }
  12. }

路径总和

递归法: 递归出口: 当前节点==null判断 当前的 target是否为0,是则返回true,否返回false

递归逻辑: DFS所有节点,每次遍历到当前节点将target-cur.val

  1. class Solution {
  2. public boolean hasPathSum(TreeNode root, int targetSum){
  3. // 处理root为空的情况
  4. if(root == null){
  5. return false;
  6. }
  7. // 叶子节点判定当前路径是否可行
  8. if(root.left==null && root.right==null){
  9. return root.val == targetSum;
  10. }
  11. return hasPathSum(root.left,targetSum-root.val) || hasPathSum(root.right,targetSum-root.val);
  12. }
  13. }

中序后序构造二叉树

思路:

  • 通过后序遍历确定每一个根节点

  • 通过DFS递归,限定范围得到左右子树

  • 递归出口 后序遍历的head > tail

  • 通过找到当前节点在中序遍历中的位置限定范围

  1. class Solution {
  2. public TreeNode buildTree(int[] inorder, int[] postorder) {
  3. int len=inorder.length;
  4. if(len==0)return null;
  5. return dfs(inorder,postorder,0,len-1,0,len-1);
  6. }

  7. TreeNode dfs(int[] inorder, int[] postorder,int head1,int tail1, int head2,int tail2){
  8. // 由于postOrder每次都会在tail-1 所以当只有一个元素则会返回
  9. if(head2>tail2)return null;
  10.  
  11. int val=postorder[tail2];
  12. TreeNode root=new TreeNode(val);
  13. if(head2==tail2)return root;

  14. int mid=0; //拆分点mid的位置是相对的,因为h1!=h2
  15. while(inorder[head1+mid]!=val)mid++;

  16. root.left=dfs(inorder, postorder, head1, head1+mid-1, head2, head2+mid-1);
  17. root.right=dfs(inorder, postorder, head1+mid+1, tail1, head2+mid, tail2-1);

  18. return root;
  19. }
  20. }

笔记:

前序中序构造二叉树类似

和中序前序类似, 只是每次的限定范围不同

二叉树填充右侧指针

递归法: 限定完美二叉树

  1. class Solution {
       public Node connect(Node root){
           if(root!=null) dfs(root.left, root.right);
           return root;
      }
       void dfs(Node left, Node right){
           if(left ==null || left.next == right) return;
           left-> next = right;
           dfs(left.left, left.right);
           dfs(left.right, right.left);
           dfs(right.left, right.right);
      }
    }

一般情况

  1. /*
  2. // Definition for a Node.
  3. class Node {
  4. public:
  5. int val;
  6. Node* left;
  7. Node* right;
  8. Node* next;

  9. Node() : val(0), left(NULL), right(NULL), next(NULL) {}

  10. Node(int _val) : val(_val), left(NULL), right(NULL), next(NULL) {}

  11. Node(int _val, Node* _left, Node* _right, Node* _next)
  12. : val(_val), left(_left), right(_right), next(_next) {}
  13. };
  14. */

  15. class Solution {
  16. public:
  17. Node* connect(Node* root) {
  18. // 空树判断
  19. if( root == nullptr ) return nullptr;
  20. // 左树为空
  21. if( root -> left != nullptr ) {
  22. if( root -> right != nullptr){
  23. // 最普遍的情况
  24. root -> left -> next = root -> right;
  25. }
  26. else
  27. // 父节点的next的第一个子节点作为next
  28. root -> left -> next = getNext(root -> next);
  29. }
  30. // 右节点不为空
  31. if( root->right != nullptr){
  32. // next
  33. root -> right -> next = getNext( root-> next );
  34. }
  35. // 先判断右节点
  36. connect(root->right);
  37. connect(root->left);

  38. return root;
  39. }
  40. // 通过父节点获取子节点的next结点
  41. Node* getNext(Node* uncle){
  42.  
  43. if( uncle == nullptr ) return nullptr;
  44.  
  45. if( uncle -> left != nullptr) return uncle->left;
  46.  
  47. if( uncle -> right != nullptr ) return uncle->right;
  48.  
  49. return getNext(uncle->next);
  50. }
  51. };

最近公共祖先

整体思路:1. 通过BFS得到每个节点和其父节点的Map

  1. 通过Set,保存p到根节点的路径

  2. 在通过获得q到根节点的路径,判断第一个包含在原来的set的节点为最先公共祖先

代码:

  1. public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) {
  2.  
  3. //记录遍历到的每个节点的父节点。
  4. Map<TreeNode, TreeNode> parent = new HashMap<>();
  5. Queue<TreeNode> queue = new LinkedList<>();
  6.  
  7. //根节点没有父节点,所以为空
  8. parent.put(root, null);
  9. //队列入队
  10. queue.add(root);
  11.  
  12. //直到两个节点都找到为止。
  13. while (!parent.containsKey(p) || !parent.containsKey(q)) {
  14. //队列是一边进一边出,这里poll方法是出队,
  15. TreeNode node = queue.poll();
  16. if (node.left != null) {
  17. //左子节点不为空,记录下他的父节点
  18. parent.put(node.left, node);
  19. //左子节点不为空,把它加入到队列中
  20. queue.add(node.left);
  21. }
  22. //右节点同上
  23. if (node.right != null) {
  24. parent.put(node.right, node);
  25. queue.add(node.right);
  26. }
  27. }
  28. Set<TreeNode> ancestors = new HashSet<>();
  29. //记录下p和他的祖先节点,从p节点开始一直到根节点。
  30. while (p != null) {
  31. ancestors.add(p);
  32. p = parent.get(p);
  33. }
  34. //查看p和他的祖先节点是否包含q节点,如果不包含再看是否包含q的父节点……
  35. while (!ancestors.contains(q))
  36. q = parent.get(q);
  37. return q;
  38. }

二叉树的序列化和反序列化

分析思路:

代码:

  1. /**
  2. * Definition for a binary tree node.
  3. * public class TreeNode {
  4. * int val;
  5. * TreeNode left;
  6. * TreeNode right;
  7. * TreeNode(int x) { val = x; }
  8. * }
  9. */
  10. public class Codec {

  11. // Encodes a tree to a single string.
  12. public String serialize(TreeNode root) {
  13. if(root == null) return "#";
  14. Queue<TreeNode> queue = new LinkedList<TreeNode>();
  15. StringBuffer res = new StringBuffer();
  16. queue.add(root);
  17. while(!queue.isEmpty()){
  18. TreeNode node = queue.poll();
  19. if(node == null){
  20. res.append("#,");
  21. continue;
  22. }
  23. res.append(node.val + ",");
  24. queue.add(node.left);
  25. queue.add(node.right);
  26. }
  27. return res.toString();
  28. }

  29. // Decodes your encoded data to tree.
  30. public TreeNode deserialize(String data) {
  31. if(data == "#") return null;
  32. Queue<TreeNode> queue = new LinkedList<>();
  33. String[] values = data.split(",");
  34. // 第一个节点
  35. TreeNode node = new TreeNode(Integer.parseInt(values[0]));
  36. queue.add(node);
  37. for(int i =1; i < values.length; i++){
  38. TreeNode treeNode = queue.poll();
  39. if(!"#".equals(values[i])){
  40. treeNode.left = new TreeNode(Integer.parseInt(values[i]));
  41. queue.add(treeNode.left);
  42. }
  43. if(!"#".equals(values[++i])){
  44. treeNode.right = new TreeNode(Integer.parseInt(values[i]));
  45. queue.add(treeNode.right);
  46. }
  47. }
  48. return node;
  49. }
  50. }

  51. // Your Codec object will be instantiated and called as such:
  52. // Codec ser = new Codec();
  53. // Codec deser = new Codec();
  54. // TreeNode ans = deser.deserialize(ser.serialize(root));

leetcode二叉树题目总结的更多相关文章

  1. 面试大总结之二:Java搞定面试中的二叉树题目

    package BinaryTreeSummary; import java.util.ArrayList; import java.util.Iterator; import java.util.L ...

  2. leetcode上题目的分类

    leetcode链表部分题目 https://zhuanlan.zhihu.com/p/29800285 <[Leetcode][链表]相关题目汇总/分析/总结> leetcode堆部分题 ...

  3. 二叉树题目集合 python

    二叉树是被考察频率非常高的数据结构.二叉树是按照“父节点-左子树&右子树”这样的方式,由根节点不断向下扩展,形成一棵树的结构.二叉树经常被提到的三种遍历方式:前序遍历.中序遍历和后序遍历,既是 ...

  4. LeetCode二叉树实现

    LeetCode二叉树实现 # 定义二叉树 class TreeNode: def __init__(self, x): self.val = x self.left = None self.righ ...

  5. LeetCode高频题目(100)汇总-Java实现

    LeetCode高频题目(100)汇总-Java实现       LeetCode高频题目(100)汇总-Java实现 目录 第01-50题 [Leetcode-easy-1] Two Sum [Le ...

  6. LeetCode算法题目解答汇总(转自四火的唠叨)

    LeetCode算法题目解答汇总 本文转自<四火的唠叨> 只要不是特别忙或者特别不方便,最近一直保持着每天做几道算法题的规律,到后来随着难度的增加,每天做的题目越来越少.我的初衷就是练习, ...

  7. LeetCode SQL题目(第一弹)

    LeetCode SQL题目 注意:Leetcode上的SQL编程题都提供了数据表的架构程序,只需要将它贴入本地数据库即可调试自己编写的程序 不管是MS-SQL Server还是MySQL都需要登陆才 ...

  8. LeetCode 二叉树,两个子节点的最近的公共父节点

    LeetCode 二叉树,两个子节点的最近的公共父节点 二叉树 Lowest Common Ancestor of a Binary Tree 二叉树的最近公共父亲节点 https://leetcod ...

  9. 已知前序(后序)遍历序列和中序遍历序列构建二叉树(Leetcode相关题目)

    1.文字描述: 已知一颗二叉树的前序(后序)遍历序列和中序遍历序列,如何构建这棵二叉树? 以前序为例子: 前序遍历序列:ABCDEF 中序遍历序列:CBDAEF 前序遍历先访问根节点,因此前序遍历序列 ...

随机推荐

  1. Mysql、Oracle锁表处理

    MySql解锁方式 1 # 1. 查看当前数据库锁表的情况 2 SELECT * FROM information_schema.INNODB_TRX; 3 # 2. 杀掉查询结果中锁表的trx_my ...

  2. Firefox 国外换为国内同步的服务器地址

    地址栏键入 about:config点击 接受风险并同意查找 identity把右侧字符串包含 firefox.com 替换为 firefox.com.cn 即换为国内同步服务器反之把 firefox ...

  3. 在 K8s 上运行 GraphScope

    本文将详细介绍:1) 如何基于 Kubernetes 集群部署 GraphScope ; 2) 背后的工作细节; 3) 如何在分布式环境中使用自己构建的 GraphScope 开发镜像. 上篇文章介绍 ...

  4. 01. 树莓派初始配置——ssh连接使用root用户登录

    ssh连接使用root用户登录 普通的"pi"用户没有权限访问某些文件夹,或者对它们只有只读功能.部分操作需要在每条命令前都要加上"sudo",非常不方便.切换 ...

  5. Python 查找算法_众里寻他千百度,蓦然回首那人却在灯火阑珊处(线性、二分,分块、插值查找算法)

    查找算法是用来检索序列数据(群体)中是否存在给定的数据(关键字),常用查找算法有: 线性查找: 线性查找也称为顺序查找,用于在无序数列中查找. 二分查找: 二分查找也称为折半查找,其算法用于有序数列. ...

  6. ASP.NET Web 应用 Docker踩坑历程

    听说Docker这玩意挺长时间了,新建Web应用的时候,也注意到有个启用Docker的选项. 前两天扫了一眼<[大话云原生]煮饺子与docker.kubernetes之间的关系>,觉得有点 ...

  7. XCTF练习题---MISC---Erik-Baleog-and-Olaf

    XCTF练习题---MISC---Erik-Baleog-and-Olaf flag:flag{#justdiffit} 解题步骤: 1.观察题目,下载附件 2.拿到手以后发现是一个没有后缀名的文件, ...

  8. CoreWCF 1.0.0 发布,微软正式支持WCF

    2022年4月28日,我们达到了一个重要的里程碑,并发布了CoreWCF的1.0.0版本.对Matt Connew (微软WCF团队成员)来说,这是5年前即 2017年1月开始的漫长旅程的结束.Mat ...

  9. java基础4.18

    1.java的"一次编写,处处运行"如何实现?: 答:java之所有能实现一次编译,到处运行,是因为java在每个系统平台上都有java虚拟机(jvm),java编译的中间文件cl ...

  10. 入行IT,一定要会Linux吗?

    现在是21世纪,是科学技术大力发展的一个时代,IT行业已经成为现在的一个非常热门的一个行业,许许多多的人都想要往IT方面发展,找IT方面相关的一个工作.很多想要接触IT行业的初学者伤透了脑筋,我该学什 ...