Day17.一刷数据结构算法(C语言版) 654最大二叉树;617合并二叉树;700二叉搜索树中的搜索;98验证二叉搜索树

本文主要是介绍Day17.一刷数据结构算法(C语言版) 654最大二叉树;617合并二叉树;700二叉搜索树中的搜索;98验证二叉搜索树,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

        又是破防的一天......


一.654最大二叉树

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

        题目链接:最大二叉树

        文章讲解:代码随想录

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

 1.思路分析

        简单来说,二叉树构建过程如下:

        构造树一般采用的是前序遍历,因为先构造中间节点,然后递归构造左子树和右子树。 

        递归三部曲:

        1)确定递归函数的参数和返回值

        参数传入的是存放元素的数组以及左右边界索引,返回该数组构造的二叉树的头结点,返回类型是指向节点的指针。

struct TreeNode* traversal(int* nums, int left, int right)

         2)确定终止条件

        当左右边界相等或左右颠倒时,返回NULL。

//若左边界大于右边界,返回NULLif(left >= right)return NULL;

        3)确定单层递归的逻辑

        第一步:先要找到数组中最大的值和对应的下标, 最大的值构造根节点,下标用来下一步分割数组。

//找出数组中最大数坐标int maxIndex = left;int i;for(i = left + 1; i < right; i++) {if(nums[i] > nums[maxIndex])maxIndex = i;}//开辟结点struct TreeNode* node = (struct TreeNode*)malloc(sizeof(struct TreeNode));//将结点的值设为最大数组数组元素node->val = nums[maxIndex];

        第二步:最大值所在的下标左区间构造左子树。

node->left = traversal(nums, left, maxIndex);

        第三步:最大值所在的下标右区间构造右子树。

node->right = traversal(nums, maxIndex + 1, right);

2.代码详解

/*** Definition for a binary tree node.* struct TreeNode {*     int val;*     struct TreeNode *left;*     struct TreeNode *right;* };*/
struct TreeNode* traversal(int* nums, int left, int right) {//若左边界大于右边界,返回NULLif(left >= right)return NULL;//找出数组中最大数坐标int maxIndex = left;int i;for(i = left + 1; i < right; i++) {if(nums[i] > nums[maxIndex])maxIndex = i;}//开辟结点struct TreeNode* node = (struct TreeNode*)malloc(sizeof(struct TreeNode));//将结点的值设为最大数组数组元素node->val = nums[maxIndex];//递归定义左孩子结点和右孩子结点node->left = traversal(nums, left, maxIndex);node->right = traversal(nums, maxIndex + 1, right);return node;
}struct TreeNode* constructMaximumBinaryTree(int* nums, int numsSize){return traversal(nums, 0, numsSize);
}

 二.617合并二叉树

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

        题目链接:合并二叉树

        文章讲解:代码随想录

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

 1.思路分析

        其实和遍历一个树逻辑是一样的,只不过传入两个树的节点,同时操作。

        这道题用哪种遍历都可以,本人以前序为例。

        递归三部曲:

        1)确定递归函数的参数和返回值

        首先要合入两个二叉树,那么参数至少是要传入两个二叉树的根节点,返回值就是合并之后二叉树的根节点。 

struct TreeNode* mergeTrees(struct TreeNode* root1, struct TreeNode* root2)

        2)确定终止条件

        因为是传入了两个树,那么就有两个树遍历的节点root1 和 root2,如果root1 == NULL 了,两个树合并就应该是 root2 了(如果root2也为NULL也无所谓,合并之后就是NULL)。

        反过来如果root2 == NULL,那么两个数合并就是root1(如果root1也为NULL也无所谓,合并之后就是NULL)。

        代码如下:

if (root1 == NULL) return root2; // 如果root1为空,合并之后就应该是root2
if (root2 == NULL) return root1; // 如果root2为空,合并之后就应该是root1

         3)确定单层递归的逻辑

        单层递归的逻辑就比较好写了,这里我们重复利用一下root1这个树,root1就是合并之后树的根节点(就是修改了原来树的结构)。

        那么单层递归中,就要把两棵树的元素加到一起。

root->val=root1->val+root2->val;

        接下来root1 的左子树是:合并root1左子树root2左子树之后的左子树。

        root1 的右子树:是 合并 root1右子树 root2右子树之后的右子树。

        最终t1就是合并之后的根节点。

root->left=mergeTrees(root1->left,root2->left);
root->right=mergeTrees(root1->right,root2->right);
return root;

 2.代码详解

/*** Definition for a binary tree node.* struct TreeNode {*     int val;*     struct TreeNode *left;*     struct TreeNode *right;* };*/
struct TreeNode* mergeTrees(struct TreeNode* root1, struct TreeNode* root2) {if(root1==NULL) return root2;if(root2==NULL) return root1;struct TreeNode* root=(struct TreeNode*)malloc(sizeof(struct TreeNode));root->val=root1->val+root2->val;root->left=mergeTrees(root1->left,root2->left);root->right=mergeTrees(root1->right,root2->right);return root;
}

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

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

        题目链接:二叉搜索树中的搜索

        文章讲解: 代码随想录

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

1.思路分析

        本题,其实就是在二叉搜索树中搜索一个节点。那么我们来看看应该如何遍历。

        递归三部曲:

        1)确定递归函数的参数和返回值

        递归函数的参数传入的就是根节点和要搜索的数值,返回的就是以这个搜索数值所在的节点。

        代码如下:

struct TreeNode* searchBST(struct TreeNode* root, int val)

         2)确定终止条件

        如果root为空,或者找到这个数值了,就返回root节点。

if (root == NULL || root->val == val) return root;

        3) 确定单层递归的逻辑

        看看二叉搜索树的单层递归逻辑有何不同。

        因为二叉搜索树的节点是有序的,所以可以有方向的去搜索。

        如果root->val 大于val,搜索左子树,如果root->val 小于 val,就搜索右子树,最后如果都没有搜索到,就返回NULL。

struct TreeNode* result = NULL;
if (root->val > val) result = searchBST(root->left, val);
if (root->val < val) result = searchBST(root->right, val);
return result;

        很多人写递归函数的时候习惯直接写searchBST(root->right, val),却忘了递归函数还有返回值。

        递归函数的返回值是什么? 是左子树如果搜索到了val,要将该节点返回。 如果不用一个变量将其接住,那么返回值不就没了。

        所以要result = searchBST(root->right, val);并在最后return result

2.代码详解

/*** Definition for a binary tree node.* struct TreeNode {*     int val;*     struct TreeNode *left;*     struct TreeNode *right;* };*/
struct TreeNode* searchBST(struct TreeNode* root, int val) {if (root == NULL || root->val == val) return root;struct TreeNode* result = NULL;if (root->val > val) result = searchBST(root->left, val);if (root->val < val) result = searchBST(root->right, val);return result;
}

 四.98验证二叉搜索树

        遇到 搜索树,一定想着中序遍历,这样才能利用上特性。 

        但本题是有陷阱的,可以自己先做一做,然后在看题解,看看自己是不是掉陷阱里了。这样理解的更深刻。

        题目链接:验证二叉搜索树

        文章讲解:代码随想录

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

 1.思路分析

        要知道中序遍历下,输出的二叉搜索树节点的数值是有序序列。

        有了这个特性,验证二叉搜索树,就相当于变成了判断一个序列是不是递增的了。

        这道题目比较容易陷入两个陷阱:

  • 陷阱1

        不能单纯的比较左节点小于中间节点,右节点大于中间节点就完事了

        我们要比较的是 左子树所有节点小于中间节点,右子树所有节点大于中间节点

        例如: [10,5,15,null,null,6,20] 这个case:

 

        节点10大于左节点5,小于右节点15,但右子树里出现了一个6 这就不符合了! 

  • 陷阱2

        样例中最小节点可能是int的最小值,如果这样使用最小的int来比较也是不行的。

        此时可以初始化比较元素为longlong的最小值。

        (不过本人写的代码并没有考虑longlong的情况,所以如果你比较顾虑,可以自行修改)

        递归三部曲:

        1)确定递归函数的参数和返回值

bool isValid(struct TreeNode* root,struct TreeNode** pre)

(悄悄话:其中,pre为用来记录前一个节点的指针的指针,我一开始本想当作全局变量放在函数前面。测试的时候没问题,但是提交的时候,面对{0}的输入,输出错误,也不知道怎么回事。如果你平时有认真看我的博客的话,你会发现我上一次也用了指针的指针来代替全局变量,错误的具体原因我也不太清楚,这也是我今天破防的原因。我回头再研究一下。我破防的另一个原因是,在第三题,我遍历的时候脑袋短路了,当时就是不明白为什么在最后要写返回值......)

        2)确定终止条件

        如果是空节点 是不是二叉搜索树呢?

        是的,二叉搜索树也可以为空!

if (root == NULL) return true;

        3)确定单层递归的逻辑

bool left = isValid(root->left,pre);if (*pre != NULL && (*pre)->val >= root->val) return false;
*pre = root; // 记录前一个节点bool right = isValid(root->right,pre);
return left && right;

2.代码详解

/*** Definition for a binary tree node.* struct TreeNode {*     int val;*     struct TreeNode *left;*     struct TreeNode *right;* };*/
bool isValid(struct TreeNode* root,struct TreeNode** pre) {if (root == NULL) return true;bool left = isValid(root->left,pre);if (*pre != NULL && (*pre)->val >= root->val) return false;*pre = root; // 记录前一个节点bool right = isValid(root->right,pre);return left && right;
}
bool isValidBST(struct TreeNode* root){struct TreeNode* pre = NULL;return isValid(root,&pre);
}

         如果你有问题或者有其他想法,欢迎评论区留言,大家可以一起探讨。

 

 

 

 

 

 

 

 

这篇关于Day17.一刷数据结构算法(C语言版) 654最大二叉树;617合并二叉树;700二叉搜索树中的搜索;98验证二叉搜索树的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!


原文地址:
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.chinasem.cn/article/928448

相关文章

Python中合并列表(list)的六种方法小结

《Python中合并列表(list)的六种方法小结》本文主要介绍了Python中合并列表(list)的六种方法小结,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋... 目录一、直接用 + 合并列表二、用 extend() js方法三、用 zip() 函数交叉合并四、用

利用Python实现Excel文件智能合并工具

《利用Python实现Excel文件智能合并工具》有时候,我们需要将多个Excel文件按照特定顺序合并成一个文件,这样可以更方便地进行后续的数据处理和分析,下面我们看看如何使用Python实现Exce... 目录运行结果为什么需要这个工具技术实现工具的核心功能代码解析使用示例工具优化与扩展有时候,我们需要将

Python实现获取带合并单元格的表格数据

《Python实现获取带合并单元格的表格数据》由于在日常运维中经常出现一些合并单元格的表格,如果要获取数据比较麻烦,所以本文我们就来聊聊如何使用Python实现获取带合并单元格的表格数据吧... 由于在日常运维中经常出现一些合并单元格的表格,如果要获取数据比较麻烦,现将将封装成类,并通过调用list_exc

使用雪花算法产生id导致前端精度缺失问题解决方案

《使用雪花算法产生id导致前端精度缺失问题解决方案》雪花算法由Twitter提出,设计目的是生成唯一的、递增的ID,下面:本文主要介绍使用雪花算法产生id导致前端精度缺失问题的解决方案,文中通过代... 目录一、问题根源二、解决方案1. 全局配置Jackson序列化规则2. 实体类必须使用Long封装类3.

Springboot实现推荐系统的协同过滤算法

《Springboot实现推荐系统的协同过滤算法》协同过滤算法是一种在推荐系统中广泛使用的算法,用于预测用户对物品(如商品、电影、音乐等)的偏好,从而实现个性化推荐,下面给大家介绍Springboot... 目录前言基本原理 算法分类 计算方法应用场景 代码实现 前言协同过滤算法(Collaborativ

Linux内核参数配置与验证详细指南

《Linux内核参数配置与验证详细指南》在Linux系统运维和性能优化中,内核参数(sysctl)的配置至关重要,本文主要来聊聊如何配置与验证这些Linux内核参数,希望对大家有一定的帮助... 目录1. 引言2. 内核参数的作用3. 如何设置内核参数3.1 临时设置(重启失效)3.2 永久设置(重启仍生效

openCV中KNN算法的实现

《openCV中KNN算法的实现》KNN算法是一种简单且常用的分类算法,本文主要介绍了openCV中KNN算法的实现,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的... 目录KNN算法流程使用OpenCV实现KNNOpenCV 是一个开源的跨平台计算机视觉库,它提供了各

springboot+dubbo实现时间轮算法

《springboot+dubbo实现时间轮算法》时间轮是一种高效利用线程资源进行批量化调度的算法,本文主要介绍了springboot+dubbo实现时间轮算法,文中通过示例代码介绍的非常详细,对大家... 目录前言一、参数说明二、具体实现1、HashedwheelTimer2、createWheel3、n

C#数据结构之字符串(string)详解

《C#数据结构之字符串(string)详解》:本文主要介绍C#数据结构之字符串(string),具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录转义字符序列字符串的创建字符串的声明null字符串与空字符串重复单字符字符串的构造字符串的属性和常用方法属性常用方法总结摘

opencv图像处理之指纹验证的实现

《opencv图像处理之指纹验证的实现》本文主要介绍了opencv图像处理之指纹验证的实现,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学... 目录一、简介二、具体案例实现1. 图像显示函数2. 指纹验证函数3. 主函数4、运行结果三、总结一、