[LeetCode]-二叉树-3

前言

记录 LeetCode 刷题中遇到的二叉树相关题目,第三篇

1302. 层数最深叶子节点的和

遍历二叉树,同时维护最深的层数 maxDepth,并用 res 维护最深层数中节点的数值和

class Solution {
    
    
    int maxDepth;
    int res;
    public void rec(TreeNode t,int depth){
    
    
        if(t == null) return;
        //遍历到比 maxDepth 更大的层数就更新maxDepth同时重置res
        if(depth > maxDepth){
    
     
            res = t.val;
            maxDepth = depth;
        }
        else if(depth == maxDepth) res += t.val;
        rec(t.left,depth + 1);
        rec(t.right,depth + 1);
    }
    public int deepestLeavesSum(TreeNode root) {
    
    
        maxDepth = -1;
        rec(root,0);
        return res;
    }
}

404.左叶子之和

public int sumOfLeftLeaves(TreeNode root) {
    
    
    if(root == null) return 0;
    //如何判断左叶子,从左叶子自身并不能知道它是左叶子,
    //只能从父亲节点才能判断
    if(root.left != null && root.left.left == null && root.left.right == null){
    
    
        return root.left.val + sumOfLeftLeaves(root.right);
    }
    return sumOfLeftLeaves(root.left) + sumOfLeftLeaves(root.right);
}

114. 二叉树展开为链表

基于先序遍历,同时维护上一个遍历到的节点,在遍历当前这个节点时,将上一个节点的 right 指向当前节点。同时当前节点的 left 要置为 null,而且在遍历到左子树时,当前节点的 right 会被修改,所以要先记录一下当前节点的左右儿子

class Solution {
    
    
    TreeNode prv; //记录先序遍历时上一个访问的数
    public void flatten(TreeNode root) {
    
    
        if(root == null) return;
        if(prv != null) prv.right = root;
        prv = root;
        TreeNode l =  root.left;
        TreeNode r =  root.right;
        root.left = null;
        flatten(l);
        flatten(r);
    }
}

109. 有序链表转换二叉搜索树

有序链表的数字序列其实就是转换后的二叉搜索树的中序遍历序列,所以可以基于中序遍历去建树,过程中再把链表上的结点的值按顺序赋值到结点上

建树的终点要根据链表的长度来判断

class Solution {
    
    
    ListNode list;
    public TreeNode sortedListToBST(ListNode head) {
    
    
        list = head;
        int length = getLength(head);
        return buildTree(0, length - 1);
    }
    public TreeNode buildTree(int left, int right) {
    
    
	    //当 left > right 其实就相当于遍历到了空结点,返回 null
        if (left > right) {
    
     
            return null;
        }
        //当[left,right]中只有偶数个数时,(left + right) >> 1 会取到两个中位数中偏小的那个数
        //但应该取偏大的那个数,所以要 (left + right + 1) >> 1
        //而当有奇数个数时,(left + right) >> 1 跟 (left + right + 1) >> 1是等价的
        int mid = (left + right + 1) >> 1;
        TreeNode root = new TreeNode();
        root.left = buildTree(left, mid - 1);
        root.val = list.val;
        list = list.next;
        root.right = buildTree(mid + 1, right);
        return root;
    }
    //计算原有序链表的长度
    public int getLength(ListNode head) {
    
    
        int count = 0;
        while (head != null) {
    
    
            count++;
            head = head.next;
        }
        return count;
    }
}

199.二叉树的右视图

在层次遍历的基础上,当每一层遍历到最后一个元素时,就把它的值加入 res

class Solution {
    
    
    private ArrayList<Integer> res = new ArrayList<>();
    public List<Integer> rightSideView(TreeNode root) {
    
    
        if(root != null){
    
    
            TreeNode t = root;
            LinkedList<TreeNode> queue = new LinkedList<>();
            LinkedList<TreeNode> queue1 = new LinkedList<>();
            queue.offer(t);
            while(!queue.isEmpty()){
    
    
                ArrayList<Integer> list = new ArrayList<>();
                while(!queue.isEmpty()){
    
    
                    t = queue.poll();
                    //当弹出t后栈为空,说明t是当前这一层的最后一个元素,也就是题目要的右视图在这一层的元素,所以把他的值加入res
                    if(queue.isEmpty()) res.add(t.val);
                    if(t.left != null) queue1.offer(t.left);
                    if(t.right != null) queue1.offer(t.right);
                }
                while(!queue1.isEmpty()){
    
    
                    queue.offer(queue1.poll());
                }
            }
        }
        return res;
    }
}

二刷时写的是下面这版代码:

public List<Integer> rightSideView(TreeNode root) {
    
    
    List<Integer> res = new ArrayList<>();
    if(root != null){
    
    
        TreeNode t = root;
        LinkedList<TreeNode> queue = new LinkedList<>();
        queue.offer(t);
        while(!queue.isEmpty()){
    
    
            int size = queue.size();
            for(int i = 0;i < size;i++){
    
    
                t = queue.poll();
                if(t.left != null) queue.offer(t.left);
                if(t.right != null) queue.offer(t.right);
            }
            res.add(t.val);
        }
    }
    return res;
}

与第一版代码的区别在于,第一版中为了遍历队列时不会遍历到本次遍历中新加入的下一层节点,使用了第二个队列来保存本次遍历中遍历到的节点的儿子节点,在本次遍历结束后再把那些儿子节点加入到原队列中

而第二版只是在遍历前先算出队列的元素个数,这些元素就是本次要遍历的节点,按照他们的个数来遍历就不怕遍历到新加入的节点了

637.二叉树的层平均值

class Solution {
    
    
    private ArrayList<Double> res = new ArrayList<>();
    public List<Double> averageOfLevels(TreeNode root) {
    
    
        if(root != null){
    
    
            TreeNode t = root;
            LinkedList<TreeNode> queue = new LinkedList<>();
            LinkedList<TreeNode> queue1 = new LinkedList<>();
            queue.offer(t);
            while(!queue.isEmpty()){
    
    
            	//tem记录每层所有节点值之和
                Double tem = 0D;
                //count记录每层结点个数
                int count = 0;
                while(!queue.isEmpty()){
    
    
                    t = queue.poll();
                    tem += t.val;
                    count++;
                    if(t.left != null) queue1.offer(t.left);
                    if(t.right != null) queue1.offer(t.right);
                }
                //每遍历完一层计算一个平均值加入res
                res.add(tem / count);
                while(!queue1.isEmpty()){
    
    
                    queue.offer(queue1.poll());
                }
            }
        }
        return res;
    }
}

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

class Solution {
    
    
    ArrayList<Integer> res = new ArrayList<>();
    public List<Integer> largestValues(TreeNode root) {
    
    
        if(root != null){
    
    
            TreeNode t = root;
            LinkedList<TreeNode> queue = new LinkedList<>();
            queue.offer(t);
            while(!queue.isEmpty()){
    
    
            	//初始化最大值为最小值
                int max = Integer.MIN_VALUE;
                int count = queue.size();
                for(int i = 1;i <= count;i++){
    
    
                    t = queue.poll();
                    //如果当前节点的值大于记录的最大值那么它的值就是新的最大值
                    max = t.val > max ? t.val : max;
                    if(t.left != null) queue.offer(t.left);
                    if(t.right != null) queue.offer(t.right);
                }
                res.add(max);
            }
        }
        return res;
    }
}

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

class Solution {
    
    
    private ArrayList<Integer> res = new ArrayList<>();
    public Node connect(Node root) {
    
    
        if(root != null){
    
    
            Node t = root;
            Node tem = null;
            LinkedList<Node> queue = new LinkedList<>();
            queue.offer(t);
            while(!queue.isEmpty()){
    
    
                int count = queue.size();
                //先让t指向当前层次第一个结点,然后从第二个结点开始遍历,tem指向新遍历到的结点,让t的next指向tem,然后再往后移动t跟tem,相当于t为前一个结点,tem为当前结点,才可以连接起来
                t = queue.poll();
                if(t.left != null) queue.offer(t.left);
                if(t.right != null) queue.offer(t.right);
                for(int i = 2;i <= count;i++){
    
    
                    tem = queue.poll();
                    t.next = tem;
                    t = tem;
                    if(tem.left != null) queue.offer(tem.left);
                    if(tem.right != null) queue.offer(tem.right);
                }
                //从循环可以看出来遍历完最后一个结点时它的next还没设定,应该设为null
                t.next = null;
            }
        }
        return root;
    }
}

117 题同样的思路同样的代码

猜你喜欢

转载自blog.csdn.net/Pacifica_/article/details/124509375