diff --git a/README.md b/README.md index 01e80da8..6b826931 100644 --- a/README.md +++ b/README.md @@ -309,6 +309,7 @@ |[0501.二叉搜索树中的众数](https://github.com/youngyangyang04/leetcode/blob/master/problems/0501.二叉搜索树中的众数.md) |二叉树 |简单|**递归/中序遍历**| |[0513.找树左下角的值](https://github.com/youngyangyang04/leetcode/blob/master/problems/0513.找树左下角的值.md) |二叉树 |中等|**递归** **迭代**| |[0515.在每个树行中找最大值](https://github.com/youngyangyang04/leetcode/blob/master/problems/0515.在每个树行中找最大值.md) |二叉树 |简单|**广度优先搜索/队列**| +|[0530.二叉搜索树的最小绝对差](https://github.com/youngyangyang04/leetcode/blob/master/problems/0530.二叉搜索树的最小绝对差.md) |二叉树搜索树 |简单|**递归** **迭代**| |[0538.把二叉搜索树转换为累加树](https://github.com/youngyangyang04/leetcode/blob/master/problems/0538.把二叉搜索树转换为累加树.md) |二叉树 |简单|**递归** **迭代**| |[0541.反转字符串II](https://github.com/youngyangyang04/leetcode/blob/master/problems/0541.反转字符串II.md) |字符串 |简单| **模拟**| |[0559.N叉树的最大深度](https://github.com/youngyangyang04/leetcode/blob/master/problems/0559.N叉树的最大深度.md) |N叉树 |简单| **递归**| @@ -336,7 +337,7 @@ # 关于作者 -大家好,我是程序员Carl,ACM 校赛、黑龙江省赛、东北四省赛金牌,和亚洲区域赛铜牌获得者,哈工大计算机硕士毕业,先后在腾讯和百度从事后端技术研发,CSDN博客专家。对算法和C++后端技术有一定的见解,利用工作之余重新刷leetcode。 +大家好,我是程序员Carl,哈工大师兄,ACM 校赛、黑龙江省赛、东北四省赛金牌、亚洲区域赛铜牌获得者,先后在腾讯和百度从事后端技术研发,CSDN博客专家。对算法和C++后端技术有一定的见解,利用工作之余重新刷leetcode。 **加我的微信,备注:「个人简单介绍」+「组队刷题」**, 拉你进刷题群,每天一道经典题目分析,而且题目不是孤立的,每一道题目之间都是有关系的,都是由浅入深一脉相承的,所以学习效果最好是每篇连续着看,也许之前你会某些知识点,但是一直没有把知识点串起来,这里每天一篇文章就会帮你把知识点串起来。我也花了不少精力来整理我的题解,**而且我不会在群里发任何广告,纯自己学习和分享。 欢迎你的加入!** diff --git a/pics/700.二叉搜索树中的搜索.png b/pics/700.二叉搜索树中的搜索.png new file mode 100644 index 00000000..1fd15466 Binary files /dev/null and b/pics/700.二叉搜索树中的搜索.png differ diff --git a/problems/0028.实现strStr().md b/problems/0028.实现strStr().md index 3b151fb8..f2e4e23a 100644 --- a/problems/0028.实现strStr().md +++ b/problems/0028.实现strStr().md @@ -36,22 +36,29 @@ KMP的经典思想就是:**当出现字符串不匹配时,可以记录一部 本篇将以如下顺序来讲解KMP, -1. 什么是KMP -2. KMP可以解决什么问题 -3. 分析KMP算法里的next数组 -4. 什么是前缀表 -5. 再分析为什么要是前缀表而不是什么哈希表其他表等等,偏偏要是前缀表。 -6. 一步一步推导前缀表是怎么求的 -7. 时间复杂度分析 -8. 前缀表与next数组的关系 -9. 如何使用next数组来做一遍匹配的过程 -10. 构造next数组 -11. 使用next数组进行匹配 -12. 前缀表统一减一(右移)的KMP实现方式 -13. 前缀表不减一的KMP实现方式 -14. 总结 -可以说步步相扣,大家要跟紧,哈哈。 +* 什么是KMP +* KMP有什么用 +* 什么是前缀表 +* 为什么一定要用前缀表 +* 如何计算前缀表 +* 前缀表与next数组 +* 使用next数组来匹配 +* 时间复杂度分析 +* 构造next数组 +* 使用next数组来做匹配 +* 前缀表统一减一 C++代码实现 +* 前缀表(不减一)C++实现 +* 总结 + + +读完本篇可以顺便,把leetcode上28.实现strStr()题目做了。 + +如果文字实在看不下去,就看我在B站上的视频吧,如下: + +* [帮你把KMP算法学个通透!(理论篇)B站](https://www.bilibili.com/video/BV1PD4y1o7nd/) +* [帮你把KMP算法学个通透!(求next数组代码篇)B站](https://www.bilibili.com/video/BV1M5411j7Xx/) + # 什么是KMP @@ -525,5 +532,7 @@ public: 可以说把KMP的每一个细微的细节都扣了出来,毫无遮掩的展示给大家了! + + > 更多算法干货文章持续更新,可以微信搜索「代码随想录」第一时间围观,关注后,回复「Java」「C++」 「python」「简历模板」「数据结构与算法」等等,就可以获得我多年整理的学习资料。 diff --git a/problems/0700.二叉搜索树中的搜索.md b/problems/0700.二叉搜索树中的搜索.md index 1dab81e2..c7ecada7 100644 --- a/problems/0700.二叉搜索树中的搜索.md +++ b/problems/0700.二叉搜索树中的搜索.md @@ -1,17 +1,35 @@ ## 题目地址 https://leetcode-cn.com/problems/search-in-a-binary-search-tree/ -## 思路 +> 二叉搜索树登场! -### 递归法 +# 700.二叉搜索树中的搜索 -先来看递归的实现方式。 +给定二叉搜索树(BST)的根节点和一个值。 你需要在BST中找到节点值等于给定值的节点。 返回以该节点为根的子树。 如果节点不存在,则返回 NULL。 -依然从递归三要素开始分析: +例如, -* 确定递归函数的参数和返回值 -* 确定终止条件 -* 确定单层递归的逻辑 + + +在上述示例中,如果要找的值是 5,但因为没有节点值为 5,我们应该返回 NULL。 + +# 思路 + +之前我们讲了都是普通二叉树,那么接下来看看二叉搜索树。 + +在[关于二叉树,你该了解这些!](https://mp.weixin.qq.com/s/_ymfWYvTNd2GvWvC5HOE4A)中,我们已经讲过了二叉搜索树。 + +二叉搜索树是一个有序树: + +* 若它的左子树不空,则左子树上所有结点的值均小于它的根结点的值; +* 若它的右子树不空,则右子树上所有结点的值均大于它的根结点的值; +* 它的左、右子树也分别为二叉搜索树 + +这就决定了,二叉搜索树,递归遍历和迭代遍历和普通二叉树都不一样。 + +本题,其实就是在二叉搜索树中搜索一个节点。那么我们来看看应该如何遍历。 + +## 递归法 1. 确定递归函数的参数和返回值 @@ -33,17 +51,25 @@ if (root == NULL || root->val == val) return root; 3. 确定单层递归的逻辑 -来看一下二叉搜索树的单层递归逻辑有何不同, 因为二叉搜索树的节点是有序的,所以可以有方向的去搜索,如果root->val > val,搜索左子树,如果root->val < val,就搜索右子树,最后如果都没有搜索到,就返回NULL。 +看看二叉搜索树的单层递归逻辑有何不同。 + +因为二叉搜索树的节点是有序的,所以可以有方向的去搜索。 + +如果root->val > val,搜索左子树,如果root->val < val,就搜索右子树,最后如果都没有搜索到,就返回NULL。 代码如下: ``` -if (root->val > val) return searchBST(root->left, val); +if (root->val > val) return searchBST(root->left, val); // 注意这里加了return if (root->val < val) return searchBST(root->right, val); return NULL; ``` -这里可能会疑惑,在递归遍历的时候,什么时候直接return 递归函数的返回值,什么时候不用加这个 return, 这取决于对递归函数的定义,这里定义的递归函数,就是返回 要查找的元素所在的节点,而这个节点就是我们所求,所以直接return递归函数的返回值。 +这里可能会疑惑,在递归遍历的时候,什么时候直接return 递归函数的返回值,什么时候不用加这个 return呢。 + +我们在[二叉树:递归函数究竟什么时候需要返回值,什么时候不要返回值?](https://mp.weixin.qq.com/s/6TWAVjxQ34kVqROWgcRFOg)中讲了,如果要搜索一条边,递归函数就要加返回值,这里也是一样的道理。 + +**因为搜索到目标节点了,就要立即return了,这样才是找到节点就返回(搜索某一条边),如果不加return,就是遍历整棵树了。** 整体代码如下: @@ -56,16 +82,23 @@ TreeNode* searchBST(TreeNode* root, int val) { } ``` -### 迭代法 +## 迭代法 -一提到二叉树遍历的迭代法,可能立刻想起使用栈来模拟深度遍历,使用队列来模拟广度遍历,其实因为二叉搜索树的特殊性,也就是节点的有序性,可以不使用辅助栈或者队列就可以写出迭代法。 +一提到二叉树遍历的迭代法,可能立刻想起使用栈来模拟深度遍历,使用队列来模拟广度遍历。 -对于一般二叉树,模拟递归的过程中还有一个回溯的过程,例如走一个左方向的分支走到头了,那么要调头,在走右分支。而对于二叉搜索树,不需要回溯的过程,因为节点的有序性就帮我们确定了搜索的方向。 +对于二叉搜索树可就不一样了,因为二叉搜索树的特殊性,也就是节点的有序性,可以不使用辅助栈或者队列就可以写出迭代法。 + +对于一般二叉树,递归过程中还有回溯的过程,例如走一个左方向的分支走到头了,那么要调头,在走右分支。 + +而**对于二叉搜索树,不需要回溯的过程,因为节点的有序性就帮我们确定了搜索的方向。** + +例如要搜索元素为3的节点,**我们不需要搜索其他节点,也不需要做回溯,查找的路径已经规划好了。** + +中间节点如果大于3就向左走,如果小于3就向右走,如图: -看如下图中的这颗二叉搜索树,例如要搜索元素为3的节点,我们不需要搜索其他节点,也不需要做回溯,查找的路径已经规划好了。 ![二叉搜索树](https://img-blog.csdnimg.cn/20200812190213280.png) -迭代法代码如下: +所以迭代法代码如下: ``` class Solution { @@ -81,34 +114,19 @@ public: }; ``` -## C++代码 +第一次看到了如此简单的迭代法,是不是感动的痛哭流涕,哭一会~ -### 递归 -``` -class Solution { -public: - 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; - } -}; -``` +# 总结 + +本篇我们介绍了二叉搜索树的遍历方式,因为二叉搜索树的有序性,遍历的时候要比普通二叉树简单很多。 + +但是一些同学很容易忽略二叉搜索树的特性,所以写出遍历的代码就未必真的简单了。 + +所以针对二叉搜索树的题目,一样要利用其特性。 + +文中我依然给出递归和迭代两种方式,可以看出写法都非常简单,就是利用了二叉搜索树有序的特点。 + +就酱,如果学到了,就转发给身边需要的同学吧! -### 迭代 -``` -class Solution { -public: - TreeNode* searchBST(TreeNode* root, int val) { - while (root != NULL) { - if (root->val > val) root = root->left; - else if (root->val < val) root = root->right; - else return root; - } - return NULL; - } -}; -``` > 更多算法干货文章持续更新,可以微信搜索「代码随想录」第一时间围观,关注后,回复「Java」「C++」 「python」「简历模板」「数据结构与算法」等等,就可以获得我多年整理的学习资料。