二叉树部分: 层序遍历(10), 226. 翻转二叉树,101. 对称二叉树

代码随想录算法训练营第13天 | 二叉树部分: 层序遍历(10), 226. 翻转二叉树,101. 对称二叉树

二叉树部分

层序遍历

广度遍历:使用队列的方式来实现,当某个节点出队的时候,让它的子节点入队

102. 二叉树的层序遍历
给你二叉树的根节点 root ,返回其节点值的 层序遍历 。 (即逐层地,从左到右访问所有节点)。

思路:使用一个变量保存每一层的数量,并且在节点出队的时候,其子节点入队
觉得这个代码没有问题,但是结果不对,感觉可能是由于队列方法或者队列的使用的问题,因为debug的时候哦,并不能满足先进先出的规则
错误原因:ArrayDeque中方法的使用问题:使用 pop() push()方法,它们表示对栈的操作,所以才不能满足先进先出的规则

public List<List<Integer>> levelOrder(TreeNode root) {
      List<List<Integer>> res=new ArrayList<>();
      Deque<TreeNode> deque=new LinkedList<>();
      if(root==null){
          return res;
      }
      deque.offer(root);//deque.push(root);
      while(!deque.isEmpty()){
           int size=deque.size();//每一层的大小
            List<Integer> list=new ArrayList<>();
           while(size>0){
               TreeNode node=deque.poll();
               list.add(node.val);
               size--;
               if(node.left!=null){
                   deque.offer(node.left);//deque.push(node.left);//对队列进行更新
               } 
               if(node.right!=null){
                 deque.offer(node.right);//错误的  deque.push(node.right);
               }
           }
           res.add(list);
      }
      return res;
    }

在这里插入图片描述
在这里插入图片描述
补充:LinkedList ArrayDeque的区别:底层数据结构不一样(链表和数组)
Deque中的push poll pop等的区别

Deque双端队列,同样实现了栈的功能
在这里插入图片描述

107. 二叉树的层序遍历 II

给你二叉树的根节点 root ,返回其节点值 自底向上的层序遍历 。 (即按从叶子节点所在层到根节点所在的层,逐层从左向右遍历)

思路:先按照上面的题做,最后对结果进行翻转
答案:哈哈哈哈哈哈哈哈哈哈哈,就是这个思路,但是直接对res结果集采用reverse()函数出现错误,集合中不支持这个方法,使用循环来解决

public List<List<Integer>> levelOrderBottom(TreeNode root) {
        List<List<Integer>> res=new LinkedList<>();
      Deque<TreeNode> deque=new LinkedList<>();
      if(root==null){
          return res;
      }
      deque.offer(root);//deque.push(root);
      while(!deque.isEmpty()){
           int size=deque.size();//每一层的大小
            List<Integer> list=new ArrayList<>();
           while(size>0){
               TreeNode node=deque.poll();
               list.add(node.val);
               size--;
               if(node.left!=null){
                   deque.offer(node.left);
               } 
               if(node.right!=null){
                 deque.offer(node.right);
               }
           }
           res.add(list);
      }
      //这边没写出来,需要注意
      List<List<Integer>> resList=new LinkedList<>();
      for(int i=res.size()-1;i>=0;i--){
          resList.add(res.get(i));
      }
      return resList;
    }

199. 二叉树的右视图

给定一个二叉树的 根节点 root,想象自己站在它的右侧,按照从顶部到底部的顺序,返回从右侧所能看到的节点值。

在这里插入图片描述
思路:还是采用层序遍历,维护一个size表示每一层的大小,当size==1的时候,把这个元素保存在结果集中

 public List<Integer> rightSideView(TreeNode root) {
      List<Integer> res=new LinkedList<>();
      Deque<TreeNode> deque=new ArrayDeque<>();
      if(root==null){
          return res;
      }
      deque.offer(root);
      while(!deque.isEmpty()){
          int size=deque.size();
          while(size>0){
              if(size==1){
                   res.add(deque.peek().val);//这边的一个判断比较重要
              }
              TreeNode node =deque.poll();
              size--;
              if(node.left!=null){
                  deque.offer(node.left);
              }
              if(node.right!=null){
                  deque.offer(node.right);
              }
          }
      }
      return res;
    }

637. 二叉树的层平均值

给定一个非空二叉树的根节点 root , 以数组的形式返回每一层节点的平均值。与实际答案相差 10-5 以内的答案可以被接受。

思路:使用变量保存每一层的元素个数和元素和,这边的10-5 这个知识点不会,补充

  public List<Double> averageOfLevels(TreeNode root) {
        List<Double> res=new LinkedList<>();
        Deque<TreeNode> deque=new ArrayDeque<>();
        if(root==null){
            return res;
        }
        deque.offer(root);
        while(!deque.isEmpty()){
            int size=deque.size();
            int sizeOr=size;
            double sum=0.0;
            while(size>0){
                TreeNode node=deque.poll();
                size--;
                sum +=node.val;
                if(size==0){
                    res.add(sum/sizeOr);//这边存在一点问题,刚开始除以size,一直出现Nan的错误,但是其实此时size=0,所以才会报错,使用一个变量来保存队列容量的原始值就可以了
                }
                if(node.left!=null){
                    deque.offer(node.left);
                }
                if(node.right!=null){
                    deque.offer(node.right);
                }
            }
        }
        return res;
    }

429. N 叉树的层序遍历

给定一个 N 叉树,返回其节点值的层序遍历。(即从左到右,逐层遍历)。树的序列化输入是用层序遍历,每组子节点都由 null 值分隔(参见示例)。

思路:n叉树的定义

public class NTreeNode{
   public int val;
   public List<NTreeNode> child;//多叉树的子节点的表示,使用列表来表示
   public NTreeNode(){};
   public NTreeNode(int val){
   this.val=val;
   }
    public NTreeNode(int val, List<NTreeNode> child){
    this.val=val;
    this.child=child;
   }
} 
public List<List<Integer>> levelOrder(Node root) {
       List<List<Integer>> res=new LinkedList<>();
       if(root==null){
           return res;
       }
       Deque<Node> deque=new ArrayDeque<>();
       deque.offer(root);
       while(!deque.isEmpty()){
           int size=deque.size();
            List<Integer> list=new LinkedList<>();
           while(size>0){
               Node node=deque.poll();
               list.add(node.val);
               size--;//注意不要忘了
               if(node.children!=null){
                   List<Node> nodeList=node.children;
                   //使用循环实现子节点的遍历
                  for(int i=0;i<nodeList.size();i++){
                      deque.offer(node.children.get(i));
                  }
               }
           }
           res.add(list);
       }
       return res;
    }

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

给定一棵二叉树的根节点 root ,请找出该二叉树中每一层的最大值。

使用一个变量保存每层中的最大值

 public List<Integer> largestValues(TreeNode root) {
     List<Integer> res=new LinkedList<>();
     Deque<TreeNode> deque=new ArrayDeque<>();
     if(root==null){
         return res;
     }
     deque.offer(root);
     while(!deque.isEmpty()){
         int size=deque.size();
         int max=Integer.MIN_VALUE;//保存每层中的最大值
          while(size>0){
              TreeNode node =deque.poll();
              if(max<node.val){
                  max=node.val;//最大值的更新
              }
              size--;
              if(node.left!=null){
                  deque.offer(node.left);
              }
              if(node.right!=null){
                  deque.offer(node.right);
              }
          }
          res.add(max);
     }
     return res;
    }

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

给定一个 完美二叉树 ,其所有叶子节点都在同一层,每个父节点都有两个子节点。二叉树定义如下,填充它的每个 next 指针,让这个指针指向其下一个右侧节点。如果找不到下一个右侧节点,则将 next 指针设置为 NULL。初始状态下,所有 next 指针都被设置为 NULL。
struct Node {
  int val;
  Node *left;
  Node *right;
  Node *next;
}

在这里插入图片描述

思路:如果size=1的话,那么next=null, 否则next等于待出队的节点

 public Node connect(Node root) {
      Deque<Node> deque=new ArrayDeque<>();
      if(root==null){
          return root;
      }
      deque.offer(root);
      while(!deque.isEmpty()){
          int size=deque.size();
          while(size>0){
              Node node=deque.poll();
              size--;
              if(size==0){
                  node.next=null;//主要的逻辑在这边,如果此时队列中没有其他的节点,表示是最右边的节点,指向null
              }else{
                  node.next=deque.peek();//否则的话指向队列中的对头元素
              }
              if(node.left!=null){
                  deque.offer(node.left);
              }

              if(node.right!=null){
                  deque.offer(node.right);
              }
          }
      }
      return root;
    }

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

给定一个二叉树,填充它的每个 next 指针,让这个指针指向其下一个右侧节点。如果找不到下一个右侧节点,则将 next 指针设置为 NULL。初始状态下,所有 next 指针都被设置为 NULL。
struct Node {
  int val;
  Node *left;
  Node *right;
  Node *next;
}

思路,这个题和上一个题是一个思路,只不过这边的二叉树结构不确定是完全二叉树,就是普通二叉树,但是对结果是没有影响的,所以采用相同的代码

public Node connect(Node root) {
           Deque<Node> deque=new ArrayDeque<>();
      if(root==null){
          return root;
      }
      deque.offer(root);
      while(!deque.isEmpty()){
          int size=deque.size();
          while(size>0){
              Node node=deque.poll();
              size--;
              if(size==0){
                  node.next=null;//主要的逻辑在这边,如果此时队列中没有其他的节点,表示是最右边的节点,指向null
              }else{
                  node.next=deque.peek();//否则的话指向队列中的对头元素
              }
              if(node.left!=null){
                  deque.offer(node.left);
              }

              if(node.right!=null){
                  deque.offer(node.right);
              }
          }
      }
      return root;
    }

104. 二叉树的最大深度

给定一个二叉树,找出其最大深度。二叉树的深度为根节点到最远叶子节点的最长路径上的节点数。说明: 叶子节点是指没有子节点的节点。

思路:二叉树的最大深度也就是二叉树层序遍历的层数,使用一个变量记录二叉树的层数

 public int maxDepth(TreeNode root) {
     int level=0;
     Deque<TreeNode> deque=new ArrayDeque<>();
     if(root==null){
         return 0;
     }
     deque.offer(root);
     while(!deque.isEmpty()){
         int size=deque.size();
         //while循环表示一层的遍历
         while(size>0){
             TreeNode node=deque.poll();
             size--;
             if(node.left!=null){
                 deque.offer(node.left);
             }
             if(node.right!=null){
                 deque.offer(node.right);
             }
         }
         level++;
     }
     return level;
    }

111. 二叉树的最小深度

给定一个二叉树,找出其最小深度。最小深度是从根节点到最近叶子节点的最短路径上的节点数量。说明:叶子节点是指没有子节点的节点。

思路:层序遍历第一次遇到的叶子节点所在的层数即为二叉树的最小深度

public int minDepth(TreeNode root) {
     int level=0;
     Deque<TreeNode> deque=new ArrayDeque<>();
     if(root==null){
         return 0;
     }
     deque.offer(root);
     while(!deque.isEmpty()){
         int size=deque.size();
         level ++;//这边提前更新深度
         while(size>0){
             TreeNode node=deque.poll();
             size--;
             if(node.left==null && node.right==null){
                 return level;//保证一但遇到叶子节点直接退出,此时的深度已经是更新的状态
             }
             if(node.left!=null){
                 deque.offer(node.left);
             }
             if(node.right!=null){
                 deque.offer(node.right);
             }
         }
     }
     return level;
    }

226. 翻转二叉树

给你一棵二叉树的根节点 root ,翻转这棵二叉树,并返回其根节点。

在这里插入图片描述
思路:正常的层序遍历的顺序是从左到右,既然要实现二叉树的翻转,试试先右再左的方法,暂时感觉就是仅仅改变了队列里面的顺序,实际上二叉树的结构并没有发生变化,感觉这个题目不适合使用层序遍历来做

public TreeNode invertTree(TreeNode root) {
      Deque<TreeNode> deque=new ArrayDeque<>();
      if(root==null){
          return root;
      }
      deque.offer(root);
      while(!deque.isEmpty()){
          int size=deque.size();
          while(size>0){
              TreeNode node=deque.poll();
              size--;
              //这边我以为先右边入队,后左边入队会改变树的左右结构,但是实际上没有
              //即只是改变了队列的顺序,实际上对于节点的左右儿子之间的关系并没有实现相应的改变
              if(node.right!=null){
                  deque.offer(node.right);
              }
               if(node.left!=null){
                  deque.offer(node.left);
              }
              
          }
      }
      return root;
    }

使用递归的方式来实现

public TreeNode invertTree(TreeNode root) {
        invertT(root);
        return root;
    }
    public void invertT(TreeNode root){
        if(root==null){
            return;
        }
        //左右子树交换
        TreeNode temp=root.left;
        root.left=root.right;
        root.right=temp;
        invertT(root.left);//左子树
        invertT(root.right);//右子树
    }

101. 对称二叉树

给你一个二叉树的根节点 root , 检查它是否轴对称。

在这里插入图片描述
思路: 使用递归的方法 递归写不出来,层序遍历的话,队列中是对称的, 感觉也实现不出来
答案:感觉这边是对于左外侧和右外侧比较 左内侧和右内测比较有印象,但是自己除了前三个if语句之外想得到的就是left.val=right.val, 但是这种情况肯定不能返回true,然后就想不出来了

public boolean isSymmetric(TreeNode root) {
        return compare(root.left, root.right);
    }

    private boolean compare(TreeNode left, TreeNode right) {

        if (left == null && right != null) {
            return false;
        }
        if (left != null && right == null) {
            return false;
        }

        if (left == null && right == null) {
            return true;
        }
        //上面的几种条件都想到了,但是想着如果左节点和右节点值相等的话直接返回true不对,然后就想不出来了
        //没想到会是这种实现
        if (left.val != right.val) {
            return false;
        }
        // 比较外侧
        boolean compareOutside = compare(left.left, right.right);
        // 比较内侧
        boolean compareInside = compare(left.right, right.left);
        return compareOutside && compareInside;
    }

总结:对称二叉树里面的递归逻辑没想出来, Deque也实现了栈的功能,注意方法的使用

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值