diff --git a/README.md b/README.md index 42de7e13..d481b3e9 100644 --- a/README.md +++ b/README.md @@ -86,6 +86,7 @@ * [二叉树:听说递归能做的,栈也能做!](https://mp.weixin.qq.com/s/c_zCrGHIVlBjUH_hJtghCg) * [二叉树:前中后序迭代方式的写法就不能统一一下么?](https://mp.weixin.qq.com/s/WKg0Ty1_3SZkztpHubZPRg) * [二叉树:层序遍历登场!](https://mp.weixin.qq.com/s/Gb3BjakIKGNpup2jYtTzog) + * [二叉树:你真的会翻转二叉树么?](https://mp.weixin.qq.com/s/6gY1MiXrnm-khAAJiIb5Bg) (持续更新中....) diff --git a/pics/235.二叉搜索树的最近公共祖先.png b/pics/235.二叉搜索树的最近公共祖先.png new file mode 100644 index 00000000..277b8165 Binary files /dev/null and b/pics/235.二叉搜索树的最近公共祖先.png differ diff --git a/problems/0102.二叉树的层序遍历.md b/problems/0102.二叉树的层序遍历.md index 416154ae..2c8cd97e 100644 --- a/problems/0102.二叉树的层序遍历.md +++ b/problems/0102.二叉树的层序遍历.md @@ -267,7 +267,7 @@ public: * 107.二叉树的层次遍历II * 199.二叉树的右视图 * 637.二叉树的层平均值 -* 589.N叉树的前序遍历 +* 429.N叉树的前序遍历 * 515.在每个树行中找最大值 虽然不能一口气打十个,打六个也还行。 diff --git a/problems/0235.二叉搜索树的最近公共祖先.md b/problems/0235.二叉搜索树的最近公共祖先.md new file mode 100644 index 00000000..b852ee67 --- /dev/null +++ b/problems/0235.二叉搜索树的最近公共祖先.md @@ -0,0 +1,98 @@ +## 链接 +https://leetcode-cn.com/problems/lowest-common-ancestor-of-a-binary-search-tree/ + +## 思路 + + +遇到这个题目首先想的是要是能自底向上查找就好了,这样就可以找到公共祖先了,可惜二叉树只能自上向低。 + +那么自上相下查找的话,如何记录祖先呢? + +做过[236. 二叉树的最近公共祖先](https://leetcode-cn.com/problems/lowest-common-ancestor-of-a-binary-tree/)题目的同学,应该知道,只要判断一个节点的左子树里有p,右子树里有q,那么当前节点就是最近公共祖先。 + +那么本题是二叉搜索树,二叉搜索树是有序的,那得好好利用一下这个特点。 + +在有序树里,如果判断一个节点的左子树里有p,右子树里有q呢? + +其实只要从上到下遍历的时候,如果 (p->val <= cur->val && cur->val <= q->val)则说明该节点cur就是最近公共祖先了。 + +理解这一点,本题就很好解了。 + +如图所示 + + + +在遍历二叉搜索树的时候就是寻找区间[p->val, q->val](注意这里是左闭又闭) + +那么如果 cur->val 大于 p->val,同时 cur->val 大于q->val,那么就应该向左遍历。(因为我们此时不知道p和q谁大,所以两个都要判断) + +代码如下: + +``` + if (cur->val > p->val && cur->val > q->val) { + return traversal(cur->left, p, q); + } +``` + +如果 cur->val 小于 p->val,同时 cur->val 小于 q->val,那么就应该向右遍历。 + +``` + } else if (cur->val < p->val && cur->val < q->val) { + return traversal(cur->right, p, q); + } +``` + +剩下的情况,我们就找到了区间使(p->val <= cur->val && cur->val <= q->val)或者是 (q->val <= cur->val && cur->val <= p->val) + +代码如下: +``` + else { + return cur; + } + +``` + +那么整体递归代码如下: + +## C++递归代码 + +(我这里特意把递归的过程抽出一个函数traversal,这样代码更清晰,有助于读者理解。) + +``` +class Solution { +private: + TreeNode* traversal(TreeNode* cur, TreeNode* p, TreeNode* q) { + if (cur->val > p->val && cur->val > q->val) { + return traversal(cur->left, p, q); + } else if (cur->val < p->val && cur->val < q->val) { + return traversal(cur->right, p, q); + } else return cur; + } +public: + TreeNode* lowestCommonAncestor(TreeNode* root, TreeNode* p, TreeNode* q) { + + return traversal(root, p, q); + } +}; +``` + + +## C++迭代法代码 + +同时给出一个迭代的版本,思想是一样的,代码如下: + +``` +class Solution { +public: + TreeNode* lowestCommonAncestor(TreeNode* root, TreeNode* p, TreeNode* q) { + while(root) { + if (root->val > p->val && root->val > q->val) { + root = root->left; + } else if (root->val < p->val && root->val < q->val) { + root = root->right; + } else return root; + } + return NULL; + } +}; +``` diff --git a/problems/链表总结篇.md b/problems/链表总结篇.md new file mode 100644 index 00000000..d1339934 --- /dev/null +++ b/problems/链表总结篇.md @@ -0,0 +1,6 @@ + +* [关于链表,你该了解这些!](https://mp.weixin.qq.com/s/ntlZbEdKgnFQKZkSUAOSpQ) + * [链表:听说用虚拟头节点会方便很多?](https://mp.weixin.qq.com/s/slM1CH5Ew9XzK93YOQYSjA) + * [链表:一道题目考察了常见的五个操作!](https://mp.weixin.qq.com/s/Cf95Lc6brKL4g2j8YyF3Mg) + * [链表:听说过两天反转链表又写不出来了?](https://mp.weixin.qq.com/s/pnvVP-0ZM7epB8y3w_Njwg) + * [链表:环找到了,那入口呢?](https://mp.weixin.qq.com/s/_QVP3IkRZWx9zIpQRgajzA)