2.树(二)

题目汇总:https://leetcode-cn.com/tag/tree/

105. 从前序与中序遍历序列构造二叉树中等[✔]

106. 从中序与后序遍历序列构造二叉树中等[✔]

107. 二叉树的层次遍历 II简单[✔]

108. 将有序数组转换为二叉搜索树简单[✔]

110. 平衡二叉树简单[✔]

111. 二叉树的最小深度简单[✔]

112. 路径总和简单[✔]

113. 路径总和 II中等

114. 二叉树展开为链表中等[✔]

116. 填充每个节点的下一个右侧节点指针中等[✔]

105. 从前序与中序遍历序列构造二叉树中等

根据一棵树的前序遍历与中序遍历构造二叉树。
注意:
你可以假设树中没有重复的元素。
例如,给出
前序遍历 preorder = [3,9,20,15,7]
中序遍历 inorder = [9,3,15,20,7]
返回如下的二叉树:[3,9,20,null,null,15,7]

思路:递归

根据中序遍历和前序遍历可以确定二叉树,具体过程为:
根据前序序列第一个结点确定根结点
根据根结点在中序序列中的位置分割出左右两个子序列
对左子树和右子树分别递归使用同样的方法继续分解

/**
 * Definition for a binary tree node.
 * public class TreeNode {
 *     int val;
 *     TreeNode left;
 *     TreeNode right;
 *     TreeNode(int x) { val = x; }
 * }
 */
class Solution {
    public TreeNode buildTree(int[] preorder, int[] inorder) {//执行用时 :13 ms, 在所有 Java 提交中击败了21.30%的用户
        if(preorder.length==0||inorder.length==0)
            return null;
        TreeNode root = new TreeNode(preorder[0]);//根据前序遍历确定根节点
        int len = preorder.length;
        for(int i=0;i

106. 从中序与后序遍历序列构造二叉树中等

根据一棵树的中序遍历与后序遍历构造二叉树。
注意:
你可以假设树中没有重复的元素。
例如,给出中序遍历 inorder = [9,3,15,20,7],后序遍历 postorder = [9,15,7,20,3]
返回如下的二叉树:[3,9,20,null,null,15,7]

思路:递归

根据中序遍历和后序遍历可以确定二叉树,具体过程为:
根据后序序列最后一个结点确定根结点
根据根结点在中序序列中的位置分割出左右两个子序列
对左子树和右子树分别递归使用同样的方法继续分解

/**
 * Definition for a binary tree node.
 * public class TreeNode {
 *     int val;
 *     TreeNode left;
 *     TreeNode right;
 *     TreeNode(int x) { val = x; }
 * }
 */
class Solution {
    public TreeNode buildTree(int[] inorder, int[] postorder) {//执行用时 :13 ms, 在所有 Java 提交中击败了17.65%的用户
        if(inorder.length == 0 || postorder.length == 0)
            return null;
        TreeNode root = new TreeNode(postorder[postorder.length-1]);
        for(int i=0;i

107. 二叉树的层次遍历 II简单

给定一个二叉树,返回其节点值自底向上的层次遍历。 (即按从叶子节点所在层到根节点所在的层,逐层从左向右遍历)
例如:给定二叉树 [3,9,20,null,null,15,7],


返回其自底向上的层次遍历为:

思路:迭代
/**
 * Definition for a binary tree node.
 * public class TreeNode {
 *     int val;
 *     TreeNode left;
 *     TreeNode right;
 *     TreeNode(int x) { val = x; }
 * }
 */
class Solution {//执行用时 :1 ms, 在所有 Java 提交中击败了98.82%的用户
    public List> levelOrderBottom(TreeNode root) {
        LinkedList> res = new LinkedList<>();
        Queue queue = new ArrayDeque<>();
        if(root != null){
            queue.add(root);//将根节点放入队列中,然后不断遍历队列
        }
        
        while(!queue.isEmpty()){
            int n = queue.size();//获取当前队列的长度,也就是当前这一层的节点个数
            List level = new ArrayList<>();
            for(int i=0;i

108. 将有序数组转换为二叉搜索树简单

将一个按照升序排列的有序数组,转换为一棵高度平衡二叉搜索树
本题中,一个高度平衡二叉树是指一个二叉树*每个节点 *的左右两个子树的高度差的绝对值不超过 1。
示例:
给定有序数组:[-10,-3,0,5,9]
一个可能的答案是:[0,-3,9,-10,null,5],它表示下面这个高度平衡二叉搜索树。

思路:递归

因为是一个按照升序排列的有序数组,转换成平衡二叉树,那么把根节点选为数组的中点即可,找到根节点,然后把数组一分为二成为左子树和右子树,进入递归即可。

/**
 * Definition for a binary tree node.
 * public class TreeNode {
 *     int val;
 *     TreeNode left;
 *     TreeNode right;
 *     TreeNode(int x) { val = x; }
 * }
 */
class Solution {
    public TreeNode sortedArrayToBST(int[] nums) {//执行用时 :0 ms, 在所有 Java 提交中击败了100.00%的用户
        return buildTree(nums, 0, nums.length-1);
    }

    private TreeNode buildTree(int[] nums, int left, int right) {
        if (left > right) {
            return null;
        }
        //当构造节点的左右子树时,对递增数组进行拆分并进行递归调用
        int mid =  left + (right - left + 1) / 2;
        TreeNode root = new TreeNode(nums[mid]);
        root.left = buildTree(nums, left, mid - 1);
        root.right = buildTree(nums, mid + 1, right);
        return root;
    }
}

110. 平衡二叉树简单

给定一个二叉树,判断它是否是高度平衡的二叉树。
本题中,一棵高度平衡二叉树定义为:
一个二叉树每个节点的左右两个子树的高度差的绝对值不超过1。
示例 :
给定二叉树 [3,9,20,null,null,15,7]
返回 true

思路:递归
/**
 * Definition for a binary tree node.
 * public class TreeNode {
 *     int val;
 *     TreeNode left;
 *     TreeNode right;
 *     TreeNode(int x) { val = x; }
 * }
 */
class Solution {
    public boolean isBalanced(TreeNode root) {//执行用时 :1 ms, 在所有 Java 提交中击败了99.78%的用户
        if(root == null)
            return true;
        if(Math.abs(Height(root.left) - Height(root.right)) > 1)
            return false;
        return isBalanced(root.left) && isBalanced(root.right);
    }
    public int Height(TreeNode root){
        if(root == null)
            return 0;
        int leftHeight = Height(root.left) + 1;
        int rightHeight = Height(root.right) + 1;
        return leftHeight > rightHeight ? leftHeight : rightHeight;
    }
}

111. 二叉树的最小深度简单

给定一个二叉树,找出其最小深度。
最小深度是从根节点到最近叶子节点的最短路径上的节点数量。
说明: 叶子节点是指没有子节点的节点。
示例:
给定二叉树 [3,9,20,null,null,15,7],
返回它的最小深度 2.

思路:递归

按照 104. 二叉树的最大深度的思路来解题出错

测试用例翻车现场

看了题解之后https://leetcode-cn.com/problems/minimum-depth-of-binary-tree/solution/li-jie-zhe-dao-ti-de-jie-shu-tiao-jian-by-user7208/

/**
 * Definition for a binary tree node.
 * public class TreeNode {
 *     int val;
 *     TreeNode left;
 *     TreeNode right;
 *     TreeNode(int x) { val = x; }
 * }
 */
 /*叶子节点的定义是左孩子和右孩子都为 null 时叫做叶子节点
当 root 节点左右孩子都为空时,返回 1
当 root 节点左右孩子有一个为空时,返回不为空的孩子节点的深度
当 root 节点左右孩子都不为空时,返回左右孩子较小深度的节点值*/
class Solution {
    public int minDepth(TreeNode root) {//执行用时 :0 ms, 在所有 Java 提交中击败了100.00%的用户
        if(root == null)
            return 0;
        if(root.left == null && root.right == null)
            return 1;
        int leftDepth = minDepth(root.left);
        int rightDepth = minDepth(root.right);
        if(root.left == null || root.right == null){         
            return leftDepth + rightDepth + 1;
        }
        return Math.min(leftDepth, rightDepth)+1;
    }
}

112. 路径总和简单

给定一个二叉树和一个目标和,判断该树中是否存在根节点到叶子节点的路径,这条路径上所有节点值相加等于目标和。
说明: 叶子节点是指没有子节点的节点。
示例:
给定如下二叉树,以及目标和 sum = 22


返回 true, 因为存在目标和为 22 的根节点到叶子节点的路径 5->4->11->2

思路:递归
/**
 * Definition for a binary tree node.
 * public class TreeNode {
 *     int val;
 *     TreeNode left;
 *     TreeNode right;
 *     TreeNode(int x) { val = x; }
 * }
 */
class Solution {
    public boolean hasPathSum(TreeNode root, int sum) {//执行用时 :0 ms, 在所有 Java 提交中击败了100.00%的用户
        if(root == null)
            return false;
        if(root.left == null && root.right == null)
            return sum - root.val == 0;
        return hasPathSum(root.left, sum - root.val) || hasPathSum(root.right, sum - root.val);
    }
}

113. 路径总和 II中等

给定一个二叉树和一个目标和,找到所有从根节点到叶子节点路径总和等于给定目标和的路径。
说明: 叶子节点是指没有子节点的节点。
示例:
给定如下二叉树,以及目标和 sum = 22


返回:
[
[5,4,11,2],
[5,8,4,5]
]

思路:DFS+递归
/**
 * Definition for a binary tree node.
 * public class TreeNode {
 *     int val;
 *     TreeNode left;
 *     TreeNode right;
 *     TreeNode(int x) { val = x; }
 * }
 */
class Solution {
    public List> pathSum(TreeNode root, int sum) {//执行用时 :4 ms, 在所有 Java 提交中击败了14.93%的用户
        List> res = new ArrayList<>();
        if (root == null) {
            return res;
        }
        // 从根结点到叶子结点的路径
        List path = new ArrayList<>();
        dfs(root, sum, path, res);
        return res;
    }

    private void dfs(TreeNode root, int sum, List path, List> res) {
        if (root == null) {
            return;
        }
        path.add(root.val);
        sum -= root.val;
        if (root.left == null && root.right == null && sum == 0) {
            res.add(path);
            return;
        
        }else{
            dfs(root.left, sum, new ArrayList<>(path), res);
            dfs(root.right, sum, new ArrayList<>(path), res);
        }
    }
}

114. 二叉树展开为链表中等

给定一个二叉树,原地将它展开为一个单链表。
例如,给定二叉树



将其展开为:


思路:递归+DFS

将左子树插入到右子树的地方
将原来的右子树接到左子树的最右边节点
考虑新的右子树的根节点,一直重复上边的过程,直到新的右子树为 null

/**
 * Definition for a binary tree node.
 * public class TreeNode {
 *     int val;
 *     TreeNode left;
 *     TreeNode right;
 *     TreeNode(int x) { val = x; }
 * }
 */
class Solution {//执行用时 :0 ms, 在所有 Java 提交中击败了100.00%的用户
    public void flatten(TreeNode root) {
        if(root == null)
            return;
        //先把左右子树捋直
        flatten(root.right);
        flatten(root.left);
        TreeNode temp = root.right;//把捋直的右子树备份一下
        root.right = root.left;//把捋直的左子树放到右边
        root.left = null;//把左子树置空
        while(root.right != null){//找到现在右子树的最后一个结点
            root = root.right;
        }
        root.right = temp;//把捋直的原来的右子树接上去
    }
}

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

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


解释:给定二叉树如图 A 所示,你的函数应该填充它的每个 next 指针,以指向其下一个右侧节点,如图 B 所示。
提示
你只能使用常量级额外空间。
使用递归解题也符合要求,本题中递归程序占用的栈空间不算做额外的空间复杂度。

思路一:递归

左子树的next就是右子树,右子树的next就是next节点的左子树

/*
// Definition for a Node.
class Node {
    public int val;
    public Node left;
    public Node right;
    public Node next;

    public Node() {}
    
    public Node(int _val) {
        val = _val;
    }

    public Node(int _val, Node _left, Node _right, Node _next) {
        val = _val;
        left = _left;
        right = _right;
        next = _next;
    }
};
*/

class Solution {
    public Node connect(Node root) //执行用时 :0 ms, 在所有 Java 提交中击败了100.00%
        if(root == null || root.left == null)
            return root;
        root.left.next = root.right;//左子树的next就是右子树
        if(root.next != null){
            root.right.next = root.next.left;//右子树的next就是next节点的左子树
        }
        connect(root.left);
        connect(root.right);
        return root;
    }
}
思路二:迭代

代码来自链接https://leetcode-cn.com/problems/populating-next-right-pointers-in-each-node/solution/dong-hua-yan-shi-san-chong-shi-xian-116-tian-chong/

class Solution {//执行用时:0 ms, 在所有 Java 提交中击败了100.00%的用户
    public Node connect(Node root) {
        if(root==null) {
            return root;
        }
        Node pre = root;
        //循环条件是当前节点的left不为空,当只有根节点
        //或所有叶子节点都出串联完后循环就退出了
        while(pre.left!=null) {
            Node tmp = pre;
            while(tmp!=null) {
                //将tmp的左右节点都串联起来
                //注:外层循环已经判断了当前节点的left不为空
                tmp.left.next = tmp.right;
                //下一个不为空说明上一层已经帮我们完成串联了
                if(tmp.next!=null) {
                    tmp.right.next = tmp.next.left;
                }
                //继续右边遍历
                tmp = tmp.next;
            }
            //从下一层的最左边开始遍历
            pre = pre.left;
        }
        return root;
    }
}

你可能感兴趣的:(2.树(二))