代码随想录算法训练营第十五天|层序遍历 10、226.翻转二叉树、101.对称二叉树

层序遍历

题目链接:102. 二叉树的层序遍历

        如何控制左右孩子入队很简单,有点像前序遍历入栈的判断,但是,如何返回结果集,就有点难度了,结果集是根据层数来保存的,所以,需要一个控制层数的方法,这里即,用一个变量len来记录每一层的节点数,然后循环加入每一层节点的孩子节点,加入完某个节点的孩子节点之后,让他出队,并让这一层的len自减和让这个出队的节点的值加入到这一层的集合中去,这样就完成了按层加入集合的实现。

/**
 * 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 {
    // 放在外面,为了与递归法参数一致,要封装方法
    List<List<Integer>> result = new ArrayList<>();
    public List<List<Integer>> levelOrder(TreeNode root) {
            if(root == null) {
                return result;
            }
            BDFOrder(root);
            return result;
	    }
        public void BDFOrder(TreeNode node) {
	        Queue<TreeNode> queue = new LinkedList<>();
	        List<Integer> level = null;
            int len = 0;            // 用来记录每一层的节点数,一遍leve存入每一层的数据大小,根据每一层的节点数,循环入队起孩子
            TreeNode temp = null;
	        queue.add(node);
	        while(!queue.isEmpty()) {
	        	level = new ArrayList<>();
                len = queue.size();
                while(len > 0) {    // 例如,此时队列中只有一个,那么将它的左右孩子入队(入队后队列中将有两个,这个交给下一个level处理),当有两个时,则循环把每一个的左右孩子入队。。。
                    temp = queue.poll();
                    if(temp.left != null) {
                        queue.add(temp.left);
                    }
                    if(temp.right != null) {
                        queue.add(temp.right);
                    }
                    level.add(temp.val);
                    len--;          // 把孩子节点入队后别忘了控制这一层的循环变量
                }
                result.add(level);
	        }
        } 
}

下面是9道层序遍历题:

107.二叉树的层次遍历II

        思路就是正常层次遍历,然后反转一下result集合就行。

public List<List<Integer>> levelOrderBottom(TreeNode root) {
        List<List<Integer>> result = new ArrayList<>();
        if(root == null) {
            return result;
        }
        BOFOrder(root,result);          // 先正常层序遍历,之后反转一下集合,即是答案
        Collections.reverse(result);
        return result;
    }
    public void BOFOrder(TreeNode root, List<List<Integer>> result) {
        Queue<TreeNode> queue = new LinkedList<>();
        List<Integer> level = null;
        TreeNode temp = null;
        int len = 0;
        queue.add(root);
        while(!queue.isEmpty()) {
            len = queue.size();
            level = new ArrayList<>();
            while(len > 0) {
                temp = queue.poll();
                level.add(temp.val);
                if(temp.left != null) {
                    queue.add(temp.left);
                }
                if(temp.right != null) {
                    queue.add(temp.right);
                }
                len--;
            }
            result.add(level);
        }
    }

199. 二叉树的右视图

        这道题第一眼想,直接一路向右遍历就完事了呗,结果一做,发现事情并不简单,题目要求的是“右视图”,不是“右子树”,单单一路向右是不行的,因为当右边没有节点而左边有节点时,左孩子也算是右视图了,这样就不能用简单的遍历了,必须一层一层的看,并且从左往右遍历,遍历到最右边的即是右视图,所以还是层序遍历的思路,开干!

public List<Integer> rightSideView(TreeNode root) {
       List<Integer> result = new ArrayList<>();
        Queue<TreeNode> queue = new LinkedList<>();
        int len = 0;
        TreeNode temp = null;
        if(root == null) {
            return result;
        }
        queue.add(root);
        // 下面就是正常的层序遍历
        while(!queue.isEmpty()) {
            len = queue.size();
            while(len > 0) {
                temp = queue.poll();
                if(temp.left != null) {
                    queue.add(temp.left);
                }
                if(temp.right !=null) {
                    queue.add(temp.right);
                }
                if(len == 1) {        // 当遍历到这一层的最后一个(因为是从左往右遍历的,所以最右边即是最后一个,也就是右视图的节点)
                    result.add(temp.val);
                }
                len--;
                
            }
        }
        return result;
    }

637.二叉树的层平均值

        还是层次遍历啦,就是简单求和然后求平均。

public List<Double> averageOfLevels(TreeNode root) {
        
        List<Double> result = new ArrayList<>();
        Queue<TreeNode> queue = new LinkedList<>();
        int len = 0;            // 记录每一层节点个数,控制孩子节点入队
        double sum = 0;         // 每一层的和
        double fenmu = 0;       // 分母
        TreeNode temp = null;
        if(root == null) {
            return result;
        }
        queue.add(root);
        while(!queue.isEmpty()) {
            len = queue.size();
            sum = 0;
            fenmu = 1.0 / len;
            while(len > 0) {
                temp = queue.poll();
                if(temp.left != null) {
                    queue.add(temp.left);
                }
                if(temp.right !=null) {
                    queue.add(temp.right);
                }
                sum +=temp.val;     
                len--;
            }
            result.add(sum*fenmu);
        }
        return result;
    
    }

429. N 叉树的层序遍历

        这题就是把孩子节点看成集合就行,当要把孩子节点入队的时候,把孩子节点这个集合遍历一遍,然后入队即可,题目中意思null只是一个分割,不用特殊处理,看题图理解就行,下面直接上官方代码了。

class Solution {
    public List<List<Integer>> levelOrder(Node root) {
        if (root == null) {
            return new ArrayList<List<Integer>>();
        }

        List<List<Integer>> ans = new ArrayList<List<Integer>>();
        Queue<Node> queue = new ArrayDeque<Node>();
        queue.offer(root);

        while (!queue.isEmpty()) {
            int cnt = queue.size();
            List<Integer> level = new ArrayList<Integer>();
            for (int i = 0; i < cnt; ++i) {
                Node cur = queue.poll();
                level.add(cur.val);
                for (Node child : cur.children) {
                    queue.offer(child);
                }
            }
            ans.add(level);
        }

        return ans;
    }
}

还有5道题,都是差不多的代码了,就先不做了。

226.翻转二叉树

题目链接:226. 翻转二叉树

1. 层序遍历法(广度优先遍历法<BFS>)

public TreeNode invertTree(TreeNode root) {
        // 1. BFS
        if(root == null) {
            return null;
        }
        TreeNode p = root;
        Queue<TreeNode> queue = new ArrayDeque<>();
        queue.add(p);
        while(!queue.isEmpty()) {   // 直接开始层序遍历
            int len = queue.size();
            while(len > 0) {
                TreeNode temp = queue.poll();
                // 孩子节点入队之前,互相交换一下位置
                TreeNode q = temp.left;
                temp.left = temp.right;
                temp.right = q;
                if(temp.left != null) {
                    queue.add(temp.left);
                } 
                if(temp.right != null) {
                    queue.add(temp.right);
                }
                len--;
            }

        }
        return root;
    }

2. 前序遍历法(深度优先遍历法<DFS>)

 public TreeNode invertTree(TreeNode root) {
        // 2. DFS(递归)法
        // 先序遍历
        if(root == null){
            return null;
        }
        swpChildrean(root);
        invertTree(root.left);      // 这个函数就是反转函数,所以就把他写成递归形式就行
        invertTree(root.right);
        return root;
    }
    void swpChildrean(TreeNode root){
        TreeNode temp = root.left;
        root.left = root.right;
        root.right = temp;
    }

101.对称二叉树

题目链接:101. 对称二叉树

1. 递归法:

        对递归法还是不是特别懂,找个时间专门突击一下递归法吧,把我对代码的理解放在注释里面了。

public boolean isSymmetric(TreeNode root) {
        /** 1. 递归法
            递归法其实与之前的递归遍历不一样,只是能用递归去做,
            因为每次都是两个两个比较,而且,两个两个比较完了之后,
            又需要同样的方式比较他们的左右孩子,所以再递归调用一遍方法
        */ 
        
        return compare(root.left, root.right);
    }
    // 递归三部曲
    // 1. 参数和返回值:由于需要两个两个比较,那么肯定需要两个参数,也刚好对应两个子树的头节点,由于是比较,而且题目也要求返回boolean,所以是boolean
    public boolean compare(TreeNode left, TreeNode right){
        // 2. 终止条件:先想想不满足条件的时候,即,当一个为空,一个不为空的时候、两个都不为空但是数值不相等的时候,返回true的时候便是两个都不为空且数值相等的时候
        if(left == null && right != null) {
            return false;
        }else if(left != null && right == null) {
            return false;
        }else if(left == null && right == null) {
            return true;
        }else if(left.val != right.val) {
            return false;
        }
        // 注意!!这里是些循环终止条件!当他们值相等的时候,例如示例1的2,不用返回true,等到
        // 3. 单层循环逻辑:接下来是要比较左子树的外侧(示例1的左3)和右子树的外侧(示例1的右3)是否相等,发现这不就和比较左右子树根节点思路一样嘛,所以直接递归即可,内侧也同理
        boolean isOut = compare(left.left, right.right);
        boolean isIn = compare(left.right, right.left);
        return isOut && isIn;       // 返回判断左右子树的结果,当一边不对称就返回false,所以是&&
    }

2. 迭代法:

        关键是在理解,两个两个比较,从外向里比较,当遇到空的时候continue,不再让它的左右孩子入队。

public boolean isSymmetric(TreeNode root) {
        // 2. 迭代法
        if(root == null){
            return false;
        }
        Queue<TreeNode> queue = new LinkedList<>();
        queue.add(root.left);
        queue.add(root.right);
        while(!queue.isEmpty()) {
            TreeNode leftNode = queue.poll();
            TreeNode rightNode = queue.poll();
            if(leftNode == null && rightNode == null) {
                continue;
            }
            // 因为已经判断都为空的情况,下面只需要判断某一个为空,则直接返回false
            // 或者都不为空,但是值不相同,也返回false
            if(leftNode == null || rightNode == null || (leftNode.val != rightNode.val)) {
                return false;
            }
            queue.add(leftNode.left);
            queue.add(rightNode.right);
            queue.add(leftNode.right);
            queue.add(rightNode.left);
        }
        return true;
    }

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值