LeetCode 二叉树/n叉树的解题思路

二叉树

  • 二叉树特点是每个节点最多只能有两棵子树,且有左右之分

  • 二叉树的数据结构如下:

    public class TreeNode {
    //节点的值
    int val;
    //左子树
    TreeNode left;
    //右子树
    TreeNode right;
    TreeNode(int x) { val = x; }
    }

  • 树节点的初始化:

    复制代码
      int val=1;
      TreeNode node = new TreeNode(val);
  • 获取树的节点node的值:

    复制代码
     int val = node.val;
  • 二叉树的节点为node,求左右子树:

    复制代码
     TreeNode right =node.right;
     TreeNode left= node.left;
  • N叉树的节点结构如下:

    class Node {
    public int val;
    public List<Node> children;
    }

树的遍历

树的遍历方式有:前序遍历(又叫先序遍历)、中序遍历、后序遍历

前序遍历:根节点,左节点,右节点。

中序遍历:左节点,根节点,右节点。

后序遍历:左节点,右节点,根节点。

递归法

树经常会用到递归。

  • 比如二叉树的中序遍历(LeetCode94)。
    先序遍历、后序遍历也类似,只是调换了节点的顺序而已。

    public class LeetCode94 {
    //list设置为成员变量,如果是方法内变量,无法一直添加元素
    private List<Integer> list = new ArrayList<>();

    复制代码
      public List<Integer> inorderTraversal(TreeNode root) {
          if (root == null) {
              return list;
          }
          //中序遍历:左节点,根节点,右节点。
          inorderTraversal(root.left);
          list.add(root.val);
          inorderTraversal(root.right);
          
          return list;
      }

    }

  • 比如N叉树的前序遍历(LeetCode589)。

    class LeetCode589{
    //list设置为成员变量,如果是方法内变量,无法一直添加元素
    private List<Integer> list = new LinkedList<>();

    复制代码
      public List<Integer> preorder(Node root) {
      if(root==null) {
              return list;
          }
          list.add(root.val);
          for (Node node : root.children) {
              preorder(node);
          }
      return list;
      }

    }

迭代法

  • 树还可以用迭代法。利用栈的先进后出解题。
    迭代法是DFS和BFS的基础,可以多学习一下。

BFS(广度优先搜索算法)。

BFS的操作步骤如下:

1、使用 Queue的 offer()方法(或者是add()方法)把树的根节点放入 Queue;

2、重复以下步骤,直到 Queue为空为止(也就是while循环条件为 !queue.isEmpty()):

(1)获取 Queue的size, 因为Queue中存放的其实就是每一层中所有的节点, size就相当于每一层的数量,也就是宽度

(2)遍历队列,直到当前这一层所有的节点都遍历完(也就是while循环条件为 size-- > 0 )

(3)在遍历过程中,使用 Queue的 offer()方法得到队列中的节点,根据节点查出它的左节点和右节点,并用offer()方法放入队列中。

题目:LeetCode104、LeetCode102

  • leetCode102:二叉树的层序遍历

    复制代码
      public List<List<Integer>> levelOrder(TreeNode root) {
          List<List<Integer>> resultList = new ArrayList<>();
          if (root==null) {
              return resultList;
          }
          Queue<TreeNode> queue = new ArrayDeque<>();
          queue.add(root);
          //遍历队列
          while (!queue.isEmpty()) {
              //此处有坑,一定要先把每一层的数量记录下来,不然队列的长度发生变化,遍历次数不一样
              int n=queue.size();
              //层序遍历,从最上层到最下层,可以用BFS,把每一层的节点放到list里面。
              //每一层都有一个list
              List<Integer> list = new ArrayList<>();
              for (int i=0;i<n;i++) {
                  //用poll拿出队列的节点
                  TreeNode node = queue.poll();
                  list.add(node.val);
                  //把当前节点的左子节点、右子节点,放入到队列中。
                  if (node.left!=null) {
                      queue.add(node.left);
                  }
                  if (node.right!=null) {
                      queue.add(node.right);
                  }
              }
              resultList.add(list);
          }
          return resultList;
    
      }

    }

  • LeetCode104:求二叉树的最大深度。

    public class LeetCode104BFS {
    public int maxDepth(TreeNode root) {
    if (root == null){
    return 0;
    }
    int depth = 0;
    Queue<TreeNode> queue= new LinkedList<>();
    //队列使用offer和poll不会抛异常
    //首先,要将根节点放入队列中。
    nodes.offer(root);
    while (!queue.isEmpty()) {
    //队列中存放的其实就是每一层中所有的节点
    //size就相当于每一层的数量
    int size = queue.size();
    //遍历一次,深度就加一
    depth++;
    //遍历队列中的数据,直到当前这一层所有的节点都遍历完
    while (size-- > 0) {
    //取出队列中的树节点
    TreeNode node = queue.poll();
    //将当前节点的左右子树,放入队列中。
    if (node!=null && node.left != null){
    queue.offer(node.left);
    }
    if (node!=null && node.right != null){
    queue.offer(node.right);
    }
    }
    }
    return depth;
    }
    }

DFS(深度优先搜索算法)

以深度优先为策略,从根节点开始一直遍历到某个叶子节点。

DFS的实现方式相比于BFS应该说大同小异,只是把 queue 换成了stack而已,stack具有后进先出LIFO(Last Input First Output)的特性,DFS的操作步骤如下:

1、把起始点放入stack;

2、重复下述3步骤,直到stack为空为止:

(1)从stack中访问栈顶的点;

(2)找出与此点邻接的且尚未遍历的点(也就是子节点),进行标记,然后全部放入stack中;

(3)如果此点没有尚未遍历的邻接点,则将此点从stack中弹出。

  • LeetCode589:N叉树的前序遍历。

    class Solution {
    public List<Integer> preorder(Node root) {
    List<Integer> list = new ArrayList<>();
    if (root == null) return list;
    //将根节点数据添加到栈中
    Stack<Node> stack = new Stack<>();
    stack.add(root);

    复制代码
          while (!stack.empty()) {
              //栈顶的数据,出栈
              root = stack.pop();
              //在list中添加栈顶数据
              list.add(root.val);
              //将子节点全部放入栈里面,由于栈是后进先出,所以后面的子节点先放入
              for (int i = root.children.size() - 1; i >= 0; i--)
                  stack.add(root.children.get(i));
          }
          
          return list;
      }

    }

参考资料

leetCode

相关推荐
CoovallyAIHub6 分钟前
避开算力坑!无人机桥梁检测场景下YOLO模型选型指南
深度学习·算法·计算机视觉
YouQian77211 分钟前
问题 C: 字符串匹配
c语言·数据结构·算法
yanxing.D16 分钟前
408——数据结构(第二章 线性表)
数据结构·算法
艾莉丝努力练剑1 小时前
【LeetCode&数据结构】二叉树的应用(二)——二叉树的前序遍历问题、二叉树的中序遍历问题、二叉树的后序遍历问题详解
c语言·开发语言·数据结构·学习·算法·leetcode·链表
YuTaoShao1 小时前
【LeetCode 热题 100】51. N 皇后——回溯
java·算法·leetcode·职场和发展
1 小时前
3D碰撞检测系统 基于SAT算法+Burst优化(Unity)
算法·3d·unity·c#·游戏引擎·sat
Tony沈哲1 小时前
OpenCV 图像调色优化实录:基于图像金字塔的 RAW / HEIC 文件加载与调色实践
opencv·算法
我就是全世界2 小时前
Faiss中L2欧式距离与余弦相似度:究竟该如何选择?
算法·faiss
boyedu2 小时前
比特币运行机制全解析:区块链、共识算法与数字黄金的未来挑战
算法·区块链·共识算法·数字货币·加密货币
KarrySmile2 小时前
Day04–链表–24. 两两交换链表中的节点,19. 删除链表的倒数第 N 个结点,面试题 02.07. 链表相交,142. 环形链表 II
算法·链表·面试·双指针法·虚拟头结点·环形链表