代码随想录算法训练营day 20|第六章 二叉树 part06

654.最大二叉树 

又是构造二叉树,昨天大家刚刚做完 中序后序确定二叉树,今天做这个 应该会容易一些, 先看视频,好好体会一下 为什么构造二叉树都是 前序遍历 

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

视频讲解:又是构造二叉树,又有很多坑!| LeetCode:654.最大二叉树_哔哩哔哩_bilibili

这个递归还是挺好写的,思路什么的很容易想到——

class Solution {
private:
    // 在左闭右开区间[left, right),构造二叉树
    TreeNode* traversal(vector<int>& nums, int left, int right) {
        if (left >= right) return nullptr;

        // 分割点下标:maxValueIndex
        int maxValueIndex = left;
        for (int i = left + 1; i < right; ++i) {
            if (nums[i] > nums[maxValueIndex]) maxValueIndex = i;
        }

        TreeNode* root = new TreeNode(nums[maxValueIndex]);

        // 左闭右开:[left, maxValueIndex)
        root->left = traversal(nums, left, maxValueIndex);

        // 左闭右开:[maxValueIndex + 1, right)
        root->right = traversal(nums, maxValueIndex + 1, right);

        return root;
    }
public:
    TreeNode* constructMaximumBinaryTree(vector<int>& nums) {
        return traversal(nums, 0, nums.size());
    }
};

617.合并二叉树 

这次是一起操作两个二叉树了, 估计大家也没一起操作过两个二叉树,也不知道该如何一起操作,可以看视频先理解一下。 优先掌握递归。

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

视频讲解:一起操作两个二叉树?有点懵!| LeetCode:617.合并二叉树_哔哩哔哩_bilibili

这个递归还是很好写,我是用的重合节点就新建一个节点的方式——

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

当然文章里面也提到了直接利用其中一个节点的方式,就是一旦两个节点都存在,就直接修改某一个节点的数值,不新建一个节点,而是利用老的节点。

使用迭代法。使用队列来实现广度遍历,因为是在root1的基础上修改的,所以只用考虑两种情况:root1不为空且root2不为空(由于考虑到执行可能的相加操作,要入队);root为空但root2不为空(那就要直接将root2赋值给root1,不用处理二者都为空或者只有root1 不为空的情况(什么也不用管)——

TreeNode* mergeTrees(TreeNode* t1, TreeNode* t2) {
        if (t1 == NULL) return t2;
        if (t2 == NULL) return t1;
        queue<TreeNode*> que;
        que.push(t1);
        que.push(t2);
        while(!que.empty()) {
            TreeNode* node1 = que.front(); que.pop();
            TreeNode* node2 = que.front(); que.pop();
            // 此时两个节点一定不为空,val相加
            node1->val += node2->val;

            // 如果两棵树左节点都不为空,加入队列
            if (node1->left != NULL && node2->left != NULL) {
                que.push(node1->left);
                que.push(node2->left);
            }
            // 如果两棵树右节点都不为空,加入队列
            if (node1->right != NULL && node2->right != NULL) {
                que.push(node1->right);
                que.push(node2->right);
            }

            // 当t1的左节点 为空 t2左节点不为空,就赋值过去
            if (node1->left == NULL && node2->left != NULL) {
                node1->left = node2->left;
            }
            // 当t1的右节点 为空 t2右节点不为空,就赋值过去
            if (node1->right == NULL && node2->right != NULL) {
                node1->right = node2->right;
            }
        }
        return t1;
    }

使用指针来实现。用二级指针来代替指向节点的指针(或者节点的地址),用一级指针来代替节点,其实我感觉这样使用并没有什么特别高明的地方,就是拗口——

void process(TreeNode** t1, TreeNode** t2) {
        if ((*t1) == NULL && (*t2) == NULL) return;
        if ((*t1) != NULL && (*t2) != NULL) {
            (*t1)->val += (*t2)->val;
        }
        if ((*t1) == NULL && (*t2) != NULL) {
            *t1 = *t2;
            return;
        }
        if ((*t1) != NULL && (*t2) == NULL) {
            return;
        }
        process(&((*t1)->left), &((*t2)->left));
        process(&((*t1)->right), &((*t2)->right));
    }
    TreeNode* mergeTrees(TreeNode* t1, TreeNode* t2) {
        process(&t1, &t2);
        return t1;
    }

700.二叉搜索树中的搜索 

递归和迭代 都可以掌握以下,因为本题比较简单, 了解一下 二叉搜索树的特性

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

视频讲解:不愧是搜索树,这次搜索有方向了!| LeetCode:700.二叉搜索树中的搜索_哔哩哔哩_bilibili

使用递归方法。不能只写三个if语句,这样还是会没有返回值,除非最后加上return NULL; 虽然三个if语句看似考虑了全部的情况,但是有时候会发生某些特殊情况,可能导致所有的if语句都不满足,所以说每个函数都需要一个默认的返回值,而只用if语句是没法实现的,要么用else来实现,要么直接return 默认值,把它当成一种规定即可——

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

使用迭代方法。这里直接用root来做指针而不是指代根节点了,这种方法明显不如递归的效率高——

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

98.验证二叉搜索树 

遇到 搜索树,一定想着中序遍历,这样才能利用上特性。 但本题是有陷阱的,可以自己先做一做,然后在看题解,看看自己是不是掉陷阱里了。这样理解的更深刻。

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

视频讲解:你对二叉搜索树了解的还不够! | LeetCode:98.验证二叉搜索树_哔哩哔哩_bilibili

这个题有好多坑,不能直接简单地用递归来解决,而是要利用二叉搜索树的中序遍历是递增的这一条件来考虑。

第一种方法是,直接将二叉树按照中序遍历储存起来,然后再判断这个序列是不是递增的——

class Solution {
public:
    vector<int> vec;
    void traversal(TreeNode* node){
        if(node==NULL) return ;
        traversal(node->left);
        vec.push_back(node->val);
        traversal(node->right);
    }
    bool isValidBST(TreeNode* root) {
        traversal(root);
        for(int i=0;i<vec.size()-1;i++){
            if(vec[i]>=vec[i+1]) return false;
        }
        return true;
    }
};

还有一种方法就是,在中序遍历的时候记录下每次的前一个节点,然后只是比较当前节点和上一个节点的大小,这一个上一个节点指的是它的中序遍历的上一个节点,每次在比较完当前节点之后,就需要更新上一个节点,那么当前节点root就被赋值给上一个节点pre,作为中序遍历的下一个节点的pre节点——

class Solution {
public:
    TreeNode* pre = NULL; // 用来记录前一个节点
    bool isValidBST(TreeNode* root) {
        if (root == NULL) return true;
        bool left = isValidBST(root->left);

        if (pre != NULL && pre->val >= root->val) return false;
        pre = root; // 记录前一个节点

        bool right = isValidBST(root->right);
        return left && right;
    }
};

至于迭代法,就是在中序遍历的时候将当前元素和上一个元素比较,来判断是否符合。

  • 28
    点赞
  • 20
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
代码随想录算法训练营是一个优质的学习和讨论平台,提供了丰富的算法训练内容和讨论交流机会。在训练营中,学员们可以通过观看视频讲解来学习算法知识,并根据讲解内容进行刷题练习。此外,训练营还提供了刷题建议,例如先看视频、了解自己所使用的编程语言、使用日志等方法来提高刷题效果和语言掌握程度。 训练营中的讨论内容非常丰富,涵盖了各种算法知识点和解题方法。例如,在第14天的训练营中,讲解了二叉树的理论基础、递归遍历、迭代遍历和统一遍历的内容。此外,在讨论中还分享了相关的博客文章和配图,帮助学员更好地理解和掌握二叉树的遍历方法。 训练营还提供了每日的讨论知识点,例如在第15天的讨论中,介绍了层序遍历的方法和使用队列来模拟一层一层遍历的效果。在第16天的讨论中,重点讨论了如何进行调试(debug)的方法,认为掌握调试技巧可以帮助学员更好地解决问题和写出正确的算法代码。 总之,代码随想录算法训练营是一个提供优质学习和讨论环境的平台,可以帮助学员系统地学习算法知识,并提供了丰富的讨论内容和刷题建议来提高算法编程能力。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* *2* *3* [代码随想录算法训练营每日精华](https://blog.csdn.net/weixin_38556197/article/details/128462133)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 100%"] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值