【LeetCode Solutions】LeetCode 106 ~ 110 题解

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

【题目描述】

给定两个整数数组 inorderpostorder,其中 inorder 是二叉树的中序遍历,postorder 是同一棵树的后序遍历,请你构造并返回这颗二叉树 。

【示例 1】

在这里插入图片描述

输入:inorder = [9,3,15,20,7], postorder = [9,15,7,20,3]
输出:[3,9,20,null,null,15,7]

【示例 2】

输入:inorder = [-1], postorder = [-1]
输出:[-1]

【提示】

1 < = i n o r d e r . l e n g t h < = 3000 1 <= inorder.length <= 3000 1<=inorder.length<=3000
p o s t o r d e r . l e n g t h = = i n o r d e r . l e n g t h postorder.length == inorder.length postorder.length==inorder.length
− 3000 < = i n o r d e r [ i ] , p o s t o r d e r [ i ] < = 3000 -3000 <= inorder[i], postorder[i] <= 3000 3000<=inorder[i],postorder[i]<=3000
inorderpostorder 都由不同的值组成
postorder 中每一个值都在 inorder
inorder 保证是树的中序遍历
postorder 保证是树的后序遍历


【分析】

LeetCode 105. 类似,唯一区别就是要通过后序遍历的最后一个节点来确定根节点。


【代码】

/**
 * Definition for a binary tree node.
 * struct TreeNode {
 *     int val;
 *     TreeNode *left;
 *     TreeNode *right;
 *     TreeNode() : val(0), left(nullptr), right(nullptr) {}
 *     TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
 *     TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
 * };
 */
class Solution {
public:
    TreeNode* buildTree(vector<int>& inorder, vector<int>& postorder) {
        return build(inorder, 0, inorder.size() - 1, postorder, 0, postorder.size() - 1);
    }

    TreeNode* build(vector<int>& in, int inSt, int inEd, vector<int>& pos, int posSt, int posEd) {
        if (posSt > posEd) return nullptr;
        TreeNode* root = new TreeNode(pos[posEd]);  // 根节点就是后序遍历的最后一个节点
        int k = 0;
        while (in[k] != pos[posEd]) k++;  // 在中序遍历中找到根节点
        int leftChildNum = k - inSt;  // 左子树节点数
        root->left = build(in, inSt, k - 1, pos, posSt, posSt + leftChildNum - 1);
        root->right = build(in, k + 1, inEd, pos, posSt + leftChildNum, posEd - 1);
        return root;
    }
};

LeetCode 107. 二叉树的层序遍历 II(中等)

【题目描述】

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

【示例 1】

在这里插入图片描述

输入:root = [3,9,20,null,null,15,7]
输出:[[15,7],[9,20],[3]]

【示例 2】

输入:root = [1]
输出:[[1]]

【示例 3】

输入:root = []
输出:[]

【提示】

树中节点数目在范围 [ 0 , 2000 ] [0, 2000] [0,2000]
− 1000 < = N o d e . v a l < = 1000 -1000 <= Node.val <= 1000 1000<=Node.val<=1000


【分析】

LeetCode 102. 类似,只需要最后将答案翻转一下即可。


【代码】

/**
 * Definition for a binary tree node.
 * struct TreeNode {
 *     int val;
 *     TreeNode *left;
 *     TreeNode *right;
 *     TreeNode() : val(0), left(nullptr), right(nullptr) {}
 *     TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
 *     TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
 * };
 */
class Solution {
public:
    vector<vector<int>> levelOrderBottom(TreeNode* root) {
        vector<vector<int>> res;
        queue<TreeNode*> Q;
        if (root) Q.push(root);
        while (!Q.empty()) {
            vector<int> v;
            int cnt = Q.size();
            while (cnt--) {
                TreeNode* t = Q.front();
                Q.pop();
                v.push_back(t->val);
                if (t->left) Q.push(t->left);
                if (t->right) Q.push(t->right);
            }
            res.push_back(v);
        }
        reverse(res.begin(), res.end());
        return res;
    }
};

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

【题目描述】

给你一个整数数组 nums,其中元素已经按升序排列,请你将其转换为一棵平衡二叉搜索树(平衡二叉树是指该树所有节点的左右子树的高度相差不超过 1)。

【示例 1】

在这里插入图片描述

在这里插入图片描述

输入:nums = [-10,-3,0,5,9]
输出:[0,-3,9,-10,null,5]
解释:[0,-10,5,null,-3,null,9] 也将被视为正确答案

【示例 2】

在这里插入图片描述

输入:nums = [1,3]
输出:[3,1]
解释:[1,null,3] 和 [3,1] 都是高度平衡二叉搜索树。

【提示】

1 < = n u m s . l e n g t h < = 1 0 4 1 <= nums.length <= 10^4 1<=nums.length<=104
− 1 0 4 < = n u m s [ i ] < = 1 0 4 -10^4 <= nums[i] <= 10^4 104<=nums[i]<=104
nums严格递增顺序排列


【分析】

为了保持平衡,每个子树的根节点都应该是节点序列的中点,然后可以递归地通过左半部分区间与右半部分区间递归地创建平衡树。


【代码】

/**
 * Definition for a binary tree node.
 * struct TreeNode {
 *     int val;
 *     TreeNode *left;
 *     TreeNode *right;
 *     TreeNode() : val(0), left(nullptr), right(nullptr) {}
 *     TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
 *     TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
 * };
 */
class Solution {
public:
    TreeNode* sortedArrayToBST(vector<int>& nums) {
        return build(nums, 0, nums.size() - 1);
    }

    TreeNode* build(vector<int>& nums, int l, int r) {
        if (l > r) return nullptr;
        int mid = l + r >> 1;
        TreeNode* root = new TreeNode(nums[mid]);
        root->left = build(nums, l, mid - 1);
        root->right = build(nums, mid + 1, r);
        return root;
    }
};

LeetCode 109. 将有序数组转换为二叉搜索树(中等)

【题目描述】

给定一个单链表的头节点 head,其中的元素按升序排序,将其转换为平衡二叉搜索树。

【示例 1】

在这里插入图片描述

输入: head = [-10,-3,0,5,9]
输出: [0,-3,9,-10,null,5]
解释: 一个可能的答案是[0,-3,9,-10,null,5],它表示所示的高度平衡的二叉搜索树。

【示例 2】

输入: head = []
输出: []

【提示】

head 中的节点数在 [ 0 , 2 ∗ 1 0 4 ] [0, 2 * 10^4] [0,2104] 范围内
− 1 0 5 < = N o d e . v a l < = 1 0 5 -10^5 <= Node.val <= 10^5 105<=Node.val<=105


【分析】

与上一题的区别就在于链表取中点的时候不能随机访问,在链表里面取中点的时间复杂度是 O ( n ) O(n) O(n) 的,如果用额外 O ( n ) O(n) O(n) 的空间开一个数组,那就和上一题一样。

如果对于每一段链表都用遍历的方式找中点,第一层所需的时间为 n / 2 n / 2 n/2,第二层为 2 ∗ n / 4 = n / 2 2 * n / 4 = n / 2 2n/4=n/2,以此类推一共有 l o g n log n logn 层,因此时间复杂度为 O ( n l o g n ) O(n log n) O(nlogn)

注意如果对于每一段区间都遍历一次求出总长度那么时间复杂度应该是 O ( n 2 ) O(n^2) O(n2),可以在函数中传入区间左右端点从而避免每次都遍历整段区间。


【代码】

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     ListNode *next;
 *     ListNode() : val(0), next(nullptr) {}
 *     ListNode(int x) : val(x), next(nullptr) {}
 *     ListNode(int x, ListNode *next) : val(x), next(next) {}
 * };
 */
/**
 * Definition for a binary tree node.
 * struct TreeNode {
 *     int val;
 *     TreeNode *left;
 *     TreeNode *right;
 *     TreeNode() : val(0), left(nullptr), right(nullptr) {}
 *     TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
 *     TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
 * };
 */
class Solution {
public:
    TreeNode* sortedListToBST(ListNode* head) {
        int n = 0;
        for (auto p = head; p; p = p->next) n++;
        return build(head, 0, n - 1);
    }

    // head 为当前区间的表头,l 为区间左端点下标,r 为区间右端点下标
    TreeNode* build(ListNode* head, int l, int r) {
        if (l > r) return nullptr;
        int mid = l + r >> 1;  // 中间节点的下标
        ListNode* p = head;
        for (int i = 0; i < mid - l; i++) p = p->next;  // 中间节点需要从位置 l 向右遍历 mid - l 次
        TreeNode* root = new TreeNode(p->val);
        root->left = build(head, l, mid - 1);
        root->right = build(p->next, mid + 1, r);
        return root;
    }
};

LeetCode 110. 平衡二叉树(简单)

【题目描述】

给定一个二叉树,判断它是否是平衡二叉树。

【示例 1】

在这里插入图片描述

输入:root = [3,9,20,null,null,15,7]
输出:true

【示例 2】

在这里插入图片描述

输入:root = [1,2,2,3,3,null,null,4,4]
输出:false

【示例 3】

输入:root = []
输出:true

【提示】

head 中的节点数在 [ 0 , 2 ∗ 1 0 4 ] [0, 2 * 10^4] [0,2104] 范围内
− 1 0 5 < = N o d e . v a l < = 1 0 5 -10^5 <= Node.val <= 10^5 105<=Node.val<=105


【分析】

只要判断每个子树的根节点左右子树的高度差是否都满足小于等于 1 即可,求解最大高度的方法就是 LeetCode 104.

注意不能只判断根节点的左右子树高度,例如下面这棵树就不是平衡的,但是根节点左右子树高度都是 3:

在这里插入图片描述


【代码】

/**
 * Definition for a binary tree node.
 * struct TreeNode {
 *     int val;
 *     TreeNode *left;
 *     TreeNode *right;
 *     TreeNode() : val(0), left(nullptr), right(nullptr) {}
 *     TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
 *     TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
 * };
 */
class Solution {
public:
    bool res = true;

    bool isBalanced(TreeNode* root) {
        getHeight(root);
        return res;
    }

    int getHeight(TreeNode* root) {
        if (!root) return 0;
        int left = getHeight(root->left), right = getHeight(root->right);
        if (abs(left - right) > 1) res = false;  // 存在一个子树的根节点其左右子树高度差大于一
        return max(left, right) + 1;
    }
};
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

柃歌

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值