代码随想录Day20-二叉树:力扣第617e、700e、98m题

617e. 合并二叉树

题目链接
代码随想录文章讲解链接

方法一:DFS递归

用时:6m25s

思路
  • 时间复杂度: O ( m i n ( m , n ) ) O(min(m,n)) O(min(m,n))
  • 空间复杂度: O ( m i n ( m , n ) ) O(min(m,n)) O(min(m,n))
C++代码
class Solution {
public:
    TreeNode* mergeTrees(TreeNode* root1, TreeNode* root2) {
        if (root1 == nullptr) return root2;
        if (root2 == nullptr) return root1;
        root1->val += root2->val;
        root1->left = mergeTrees(root1->left, root2->left);
        root1->right = mergeTrees(root1->right, root2->right);
        return root1;
    }
};

方法二:BFS迭代

思路

首先要搞清楚要返回的对象,我们最终要返回root1,即我们要将合并得到的二叉树存储在原来以root1为根节点的二叉树(树1)中,因为为了节省空间,不新建二叉树,所以直接原地修改。
既然我们最终要将结果存放在树1中,那边迭代过程中节点修改的逻辑就要理清楚:

  1. 使用队列存放两棵树的节点,对应位置的节点存放在一起,且树1的节点在树2的节点前面,这意味着树1的节点比树2的节点先入队。并且队列中我们不存放空节点,原因见后面。
  2. 迭代的时候,每次弹出队头前两个节点,分别为node1和node2。由于我们树1最后是我们要返回的结果,所以我们要修改的是树1的节点,无需更改树2的节点。将node1的值更改为node1的值加node2的值。
  3. 接下来是处理当前两个节点的子节点。注意,如果node2不存在左(右)节点,那么node1的左(右)节点以及以左(右)节点为根节点的子树都不用进行任何修改。所以如果node2不存在左(右)节点的话,直接跳过,无需将node1的左(右)节点入队。
  4. 如果node2存在左(右)节点,当node1也存在左(右)节点时,将两者都入列。如果node1不存在左(右)节点时,直接让node1的左(右)节点赋值为node2的左(右)节点,且后续的子树也直接等于node2左(右)子树,不用进行其他处理,所以也不用入队。

本题的BFS解法与二叉树BFS遍历稍有不同,主要的不同点在于并不是每个节点都会入队,当我们确定了两棵树中某一棵树的子树为空时,后续的节点全都无需入队判断,直接赋值后跳过即可。

  • 时间复杂度: O ( m i n ( m , n ) ) O(min(m,n)) O(min(m,n))
  • 空间复杂度: O ( m i n ( m , n ) ) O(min(m,n)) O(min(m,n))
C++代码
class Solution {
public:
    TreeNode* mergeTrees(TreeNode* root1, TreeNode* root2) {
        if (root1 == nullptr) return root2;
        if (root2 == nullptr) return root1;
        queue<TreeNode*> que;
        que.push(root1);
        que.push(root2);
        while (!que.empty()) {
            TreeNode* node1 = que.front();
            que.pop();
            TreeNode* node2 = que.front();
            que.pop();

            node1->val += node2->val;
            if (node2->left) {  // 只有node2左节点存在才需处理
                if (node1->left) {  // 如果node1也存在左节点
                    que.push(node1->left);
                    que.push(node2->left);
                } else node1->left = node2->left;  // 如果node1不存在左节点
            }
            if (node2->right) {  // 只有node2右节点存在才需处理
                if (node1->right) {  // 如果node1也存在右节点
                    que.push(node1->right);
                    que.push(node2->right);
                } else node1->right = node2->right;  // 如果node1不存在右节点
            }
        }
        return root1;
    }
};

看完讲解的思考

本题的关键点在于其中一个节点为空直接返回另外一个节点,这一点做题的时候没有想到。

代码实现遇到的问题

无。


700e. 二叉搜索树中的搜索

题目链接
代码随想录文章讲解链接

方法一:DFS递归法

思路

目标值比当前节点小就继续搜索左子树,大就搜索右子树。

  • 时间复杂度: O ( n ) O(n) O(n),最坏情况当树呈链状。
  • 空间复杂度: O ( n ) O(n) O(n)
C++代码
class Solution {
public:
    TreeNode* searchBST(TreeNode* root, int val) {
        if (root == nullptr) return nullptr;
        if (root->val == val) return root;
        return root->val < val ? searchBST(root->right, val) : searchBST(root->left, val);
    }
};

方法二:迭代法

思路

由于每次判断只与当前节点有关,所以本题的迭代法无需使用栈,直接迭代更新当前节点即可。

  • 时间复杂度: O ( n ) O(n) O(n)
  • 空间复杂度: O ( 1 ) O(1) O(1)
C++代码
class Solution {
public:
    TreeNode* searchBST(TreeNode* root, int val) {
        while (root) {
            if (root->val == val) return root;
            else if (root->val < val) root = root->right;
            else root = root->left;
        }
        return nullptr;
    }
};

看完讲解的思考

一开始思维固化了,想到DFS迭代法就建立了一个栈,但是本题用迭代法根本就不需要栈。

代码实现遇到的问题

无。


98m. 验证二叉搜索树

题目链接
代码随想录文章讲解链接

方法一:DFS递归法

用时:19m1s

思路

每次递归先判断当前节点的值是否位于上下界之间,否则返回false;然后再递归判断左右节点,递归的时候更新上下界。注意本题陷阱,要使用long long

  • 时间复杂度: O ( n ) O(n) O(n)
  • 空间复杂度: O ( n ) O(n) O(n)
C++代码
class Solution {
private:
    bool _isValidBST(TreeNode* node, long long minVal, long long maxVal) {
        if (node->val <= minVal || node->val >= maxVal) return false;
        bool leftFlag = true;
        bool rightFlag = true;
        if (node->left) leftFlag = _isValidBST(node->left, minVal, node->val);
        if (node->right) rightFlag = _isValidBST(node->right, node->val, maxVal);
        return leftFlag && rightFlag;
    }

public:
    bool isValidBST(TreeNode* root) {
        return _isValidBST(root, LLONG_MIN, LLONG_MAX);
    }
};

方法二:中序遍历递归法

思路

BST的性质:BST中序遍历的结果是有序数组。我们可以利用这一条性质来判断一棵树是不是BST。
在中序遍历过程中,用minVal记录当前的下界,递归过程中不断更新,且当前节点需要大于minVal。

  • 时间复杂度: O ( n ) O(n) O(n)
  • 空间复杂度: O ( n ) O(n) O(n)
C++代码
class Solution {
private:
    long long minVal = LLONG_MIN;
public:
    bool isValidBST(TreeNode* root) {
        if (root == nullptr) return true;
        bool leftFlag = isValidBST(root->left);
        if (root->val <= minVal) return false;
        minVal = root->val;
        bool rightFlag = isValidBST(root->right);
        return leftFlag && rightFlag;
    }
};

方法三:中序遍历迭代法

思路

用一个指针记录中序遍历的前一个节点,然后比较当前节点是否大于前一个节点的值。

  • 时间复杂度: O ( n ) O(n) O(n)
  • 空间复杂度: O ( n ) O(n) O(n)
C++代码
class Solution {
public:
    bool isValidBST(TreeNode* root) {
        stack<TreeNode*> st;
        TreeNode* cur = root;
        TreeNode* pre = nullptr;  // 用于记录中序遍历中前一个节点
        while (cur || !st.empty()) {
            if (cur) {
                st.push(cur);
                cur = cur->left;
            } else {
                cur = st.top();
                st.pop();
                if (pre && cur->val <= pre->val) return false;  // 当前节点的值需要大于前一个节点
                pre = cur;
                cur = cur->right;
            }
        }
        return true;
    }
};

看完讲解的思考

代码实现遇到的问题


最后的碎碎念

今天刮台风“苏拉”,宅在宿舍。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值