代码随想录第二十天 LeetCode513、112、113、106、105

654. 最大二叉树

在这里插入图片描述
本题已经给出了构造的要求,首先找到最大值,接着根据最大值分割数组,再递归构建左右子树。
和之前的根据后序和中序数组构造二叉树相似,下面给出代码:

class Solution {
public:
    int getindedx(vector<int> vec){
        int val = INT_MIN;
        int ans;
        for(int i = 0; i < vec.size(); i++){
            if(vec[i] > val){
                ans = i;
                val = vec[i];
            }
        }
        return ans;
    }
    TreeNode* constructMaximumBinaryTree(vector<int>& nums) {
        if(nums.size() == 0) return NULL;
        int rootindex = getindedx(nums);
        TreeNode* root = new TreeNode(nums[rootindex]);
        if(nums.size() == 1) return root;
        vector<int> leftvec(nums.begin() , nums.begin() + rootindex);
        vector<int> rightvec(nums.begin() + rootindex + 1, nums.end());
        root->left = constructMaximumBinaryTree(leftvec);
        root->right = constructMaximumBinaryTree(rightvec);
        return root;
    }
};

这里我自己定义了一个寻找最大值的函数,其实没有必要,并且在性能和代码上还有很大的优化空间。下面是使用数组下标进行递归的优化代码:

class Solution {
public:
    TreeNode* traversal(vector<int>& nums, int left, int right){
        if(left >= right) return NULL;
        int maxindex = left;
        for(int i = left + 1; i < right; i++){
            if(nums[maxindex] < nums[i]) maxindex = i;
        }
        TreeNode* root = new TreeNode(nums[maxindex]);
        root->left = traversal(nums, left, maxindex);
        root->right = traversal(nums, maxindex + 1, right);
        return root;
    }
    TreeNode* constructMaximumBinaryTree(vector<int>& nums) {
        return traversal(nums, 0, nums.size());
    }
};

这样节省了额外数组的内存开销,但是需要注意寻找最大值下标的时候的循环范围是left + 1right

617. 合并二叉树

本题主要是同时对两棵二叉树进行处理,实际上与处理一颗二叉树差不多,因为遍历两棵树的时候节点处理的顺序是相同的。
使用递归来写,本题使用前中后序遍历都可以,下面是递归三部曲:

  1. 输入输出:不需要额外再写一个递归函数,直接使用题目给的即可:TreeNode* mergeTrees(TreeNode* root1, TreeNode* root2)
  2. 终止条件:这里的终止条件不能写两者都为空,这样在本题中没有意义,而是当两者其中一个为空时的处理
  3. 单层递归逻辑:这里使用前序,构造好节点后再递归构造左右子树

我自己写的是创建一个新的树来输出结果:

TreeNode* mergeTrees(TreeNode* root1, TreeNode* root2) {
        if(root1 == NULL || root2 == NULL){
            if(root1 == NULL) return root2;
            else if(root2 == NULL) return root1;
            else return NULL;
        }
        int val1 = 0;
        int val2 = 0;
        if(root1) val1 = root1->val;
        if(root2) val2 = root2->val;
        TreeNode* root = new TreeNode(val1 + val2);
        root->left = mergeTrees(root1->left , root2->left);
        root->right = mergeTrees(root1->right , root2->right);
        //if(root1->left || root2->left) root->left = mergeTrees(root1->left , root2->left);
        //if(root1->right || root2->right) root->right = mergeTrees(root1->right , root2->right);
        return root;
    }

这里说一下我对终止条件的判断,以及对空节点的处理的理解:

  • 如果在终止条件里已经对空节点处理了,那么在递归左右孩子的时候可以不用加上if(root->left)这种代码;
  • 如果终止条件中需要对符合条件的节点进行处理的话,一般情况下这个节点不会为空节点,所以后面对左右孩子的递归不需要加上if(root->left)这种代码;
  • 当需要使用节点内的value时,需要注意空节点的问题,如果有以上两种情况的话实际上可以忽略,因为已经提前确保当前遍历节点不是空节点了。
  • 有时候也需要根据递归函数的返回值类型来决定

只是一些自己刷题的感想,也不一定对。

上述代码也可以进一步简化,比如终止条件那里,不需要对左右节点都为NULL的情况返回false,因为如果root1为NULL返回root2,root2为NULL返回root1已经包含了两者都为空的情况。另外可以直接对其中一个树直接操作,不用去额外构造一棵树。
代码如下:

TreeNode* mergeTrees(TreeNode* root1, TreeNode* root2) {
        if(root1 == NULL) return root2;
        if(root2 == NULL) return root1;
        root1->val += root2->val;
        root1->left = mergeTrees(root1->left, root2->left);
        root1->right = mergeTrees(root1->right, root2->right);
        return root1;
    }

这样就看起来很简洁了。

700. 二叉搜索树中的搜索

本题使用迭代法来做甚至不需要使用队列或者栈来储存节点,因为二叉搜索树的特性,代码也非常简洁,也就不详细说了,代码如下:

TreeNode* searchBST(TreeNode* root, int val) {
        while(root){
            if(val < root->val) root = root->left;
            else if(val > root->val) root = root->right;
            else return root;;
        }
        return NULL;
    }

下面详细说一下递归法。
本题递归部分顺序,因为BST本身就是有序的,所以不需要确定前中后序。这里顺便说一下一个特性,在下一题中非常重要:BST的中序遍历是一个递增的数组
递归三部曲:

  1. 输入输出:使用函数本身来递归,TreeNode* searchBST(TreeNode* root, int val)
  2. 终止条件:先补充一个概念:空节点是一颗BST也是一颗完全二叉树、满二叉树;所以当节点为空时返回,当节点的值等于target时返回;
  3. 单层递归逻辑:由于BST的特性,当root->val大于target时,说明需要找的节点一定在root节点的左边,反之则在右边,这样就确定了左右递归的逻辑

递归代码如下:

TreeNode* searchBST(TreeNode* root, int val) {
        if(root == NULL || root->val == val) return root;
        TreeNode* ans = NULL;
        if(val < root->val) ans = searchBST(root->left, val);
        if(val > root->val) ans = searchBST(root->right, val);
        return ans;
    }

这里需要新定义一个TreeNode* ans来接收左右孩子遍历的结果,否则在遍历完左或者右孩子之后没有返回值。

98. 验证二叉搜索树

本题解题的核心思想就是上面提到的BST的中序遍历是递增的,所以思路是在遍历的时候将当前节点的值与前一个结点进行对比,如果大于则符合BST,如果小于则直接返回false。
最简单的写法就是遍历整颗二叉树,然后将结果输出到数组中,最后判断是否是BST,代码如下:

class Solution {
private:
    vector<int> vec;
    void traversal(TreeNode* root) {
        if (root == NULL) return;
        traversal(root->left);
        vec.push_back(root->val); // 将二叉搜索树转换为有序数组
        traversal(root->right);
    }
public:
    bool isValidBST(TreeNode* root) {
        vec.clear(); // 不加这句在leetcode上也可以过,但最好加上
        traversal(root);
        for (int i = 1; i < vec.size(); i++) {
            // 注意要小于等于,搜索树里不能有相同元素
            if (vec[i] <= vec[i - 1]) return false;
        }
        return true;
    }
};

本题也可以使用双指针,在一个函数里直接完成解题步骤。因为BST的特性,所以按照中序遍历的递归来写递归函数。
递归三部曲:

  1. 输入输出:bool isValidBST(TreeNode* root),直接使用主函数,输入自然是结点,输出是bool
  2. 终止条件:前面也说了,空结点也是BST,所以终止条件为if(root == NULL)
  3. 单层递归逻辑:使用一个pre指针保存前一个结点,然后进行比较,按照中序的顺序写递归函数体

下面是具体代码:

	TreeNode* pre = NULL;
    bool isValidBST(TreeNode* root) {
        if(root == NULL) return true;
        bool left = isValidBST(root->left);
        if(pre && pre->val >= root->val) return false;
        pre = root;
        bool right = isValidBST(root->right);
        return left && right;
    }

总结

一个是返回值和返回类型的问题:最后一题是需要处理递归的结果的,所以需要返回值,并且同时需要两个遍历来接收左右孩子遍历的结果返回上一层;700. 二叉搜索树中的搜索中需要定义一个结点来存放返回值,如果在if语句中直接返回是不符合语法的。
一个是终止条件和空结点的问题:一般情况来说:如果让空节点(空指针)进入递归,就不加if,如果不让空节点进入递归,就加if限制一下, 终止条件也会相应的调整。
有点累,但还是要咬牙坚持,调整一下状态继续干二叉树!

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值