刷题日期:上午7:49 2021年5月30日星期日
个人刷题记录,代码收集,来源皆为leetcode
经过多方讨论和请教,现在打算往Java方向发力
主要答题语言为Java
题目:
剑指 Offer 68 - I. 二叉搜索树的最近公共祖先
难度简单131
给定一个二叉搜索树, 找到该树中两个指定节点的最近公共祖先。
百度百科中最近公共祖先的定义为:“对于有根树 T 的两个结点 p、q,最近公共祖先表示为一个结点 x,满足 x 是 p、q 的祖先且 x 的深度尽可能大(一个节点也可以是它自己的祖先)。”
例如,给定如下二叉搜索树: root = [6,2,8,0,4,7,9,null,null,3,5]
示例 1:
输入: root = [6,2,8,0,4,7,9,null,null,3,5], p = 2, q = 8
输出: 6
解释: 节点 2 和节点 8 的最近公共祖先是 6。
示例 2:
输入: root = [6,2,8,0,4,7,9,null,null,3,5], p = 2, q = 4
输出: 2
解释: 节点 2 和节点 4 的最近公共祖先是 2, 因为根据定义最近公共祖先节点可以为节点本身。
说明:
- 所有节点的值都是唯一的。
- p、q 为不同节点且均存在于给定的二叉搜索树中。
题目分析
二叉搜索树的特点就是已经是有序的了。
二叉树题目,很有可能还涉及到递归。在搜索中,分情况,如果左边小于根,右边大于根,那么直接返回根节点,如果左边右边都大于,那么去右边找,如果左边右边都小于,那么去左边找。
题目限定了输入肯定存在,那么先找到哪个节点,哪个节点就是最近的公共节点。
初始解答:
没白练啊没白练,完美收官,一次跑通
/**
* Definition for a binary tree node.
* public class TreeNode {
* int val;
* TreeNode left;
* TreeNode right;
* TreeNode(int x) { val = x; }
* }
*/
class Solution {
TreeNode res;
public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) {
if(p.val > q.val) {
TreeNode tmp = p;
p = q;
q = tmp;
} //确保p小q大
if(root.val <= q.val && root.val >= p.val) return root;
if(root.val < p.val) res = lowestCommonAncestor(root.right, p, q);
if(root.val > p.val) res = lowestCommonAncestor(root.left, p, q);
return res;
}
}
执行结果:通过
显示详情 添加备注
执行用时:6 ms, 在所有 Java 提交中击败了100.00%的用户
内存消耗:38.6 MB, 在所有 Java 提交中击败了96.88%的用户
学习他人:
方法一:
宝石L2 (编辑过)2020-02-14
Java题解 简单明了
利用好二叉搜索树的性质。
public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) {
if (root == null)
return null;
if (root.val > p.val && root.val > q.val)
return lowestCommonAncestor(root.left, p, q);
if (root.val < p.val && root.val < q.val)
return lowestCommonAncestor(root.right, p, q);
return root;
}
方法二:
JoCai 2021-02-21
Java:
执行用时:6 ms, 在所有 Java 提交中击败了100.00%的用户
内存消耗:39.3 MB, 在所有 Java 提交中击败了17.36%的用户
class Solution {
public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) {
if(root==null) return null;
if(p==root || q==root) return root;
//两个结点都在当前结点的左边
if(p.val<root.val && q.val<root.val){
return lowestCommonAncestor(root.left,p,q);//找左边
}
//两个结点都在当前结点的右边
else if(p.val>root.val && q.val>root.val){
return lowestCommonAncestor(root.right,p,q);//找右边
}
//或者一左一右
else{
return root;
}
}
}
方法三:
2020-03-13
可以写几个case然后画个图看看,很容易 发现规律
class Solution {
public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) {
//当p,q都比root小时,根据二叉搜索树的性质,则p和q的公共祖先一定在root的左子树上
if (p.val < root.val && q.val < root.val) {
return lowestCommonAncestor(root.left, p, q);
}
//同理,当p,q都比root大,则去root的右子树上找。
if (p.val > root.val && q.val > root.val) {
return lowestCommonAncestor(root.right, p, q);
}
//如果p或q等于root了,则说明这个等于的节点就是公共祖先
//否则则p和q是在root的两边,则root是公共祖先
if (p.val == root.val) {
return p;
} else if (q.val == root.val) {
return q;
} else {
return root;
}
}
}
方法四:
Roderland 2020-08-06
迭代版
class Solution {
public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) {
// if (p==root||q==root) return root;
// if (p==q) return p;
while (true) {
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;
}
}
}
方法五
K神
作者:jyd
链接:https://leetcode-cn.com/problems/er-cha-sou-suo-shu-de-zui-jin-gong-gong-zu-xian-lcof/solution/mian-shi-ti-68-i-er-cha-sou-suo-shu-de-zui-jin-g-7/
来源:力扣(LeetCode)
方法一:迭代
class Solution {
public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) {
while(root != null) {
if(root.val < p.val && root.val < q.val) // p,q 都在 root 的右子树中
root = root.right; // 遍历至右子节点
else if(root.val > p.val && root.val > q.val) // p,q 都在 root 的左子树中
root = root.left; // 遍历至左子节点
else break;
}
return root;
}
}
优化:若可保证 p.val < q.val ,则在循环中可减少判断条件。
class Solution {
public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) {
if(p.val > q.val) { // 保证 p.val < q.val
TreeNode tmp = p;
p = q;
q = tmp;
}
while(root != null) {
if(root.val < p.val) // p,q 都在 root 的右子树中
root = root.right; // 遍历至右子节点
else if(root.val > q.val) // p,q 都在 root 的左子树中
root = root.left; // 遍历至左子节点
else break;
}
return root;
}
}
方法二:递归
class Solution {
public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) {
if(root.val < p.val && root.val < q.val)
return lowestCommonAncestor(root.right, p, q);
if(root.val > p.val && root.val > q.val)
return lowestCommonAncestor(root.left, p, q);
return root;
}
}
题目:
剑指 Offer 68 - II. 二叉树的最近公共祖先
难度简单258
给定一个二叉树, 找到该树中两个指定节点的最近公共祖先。
百度百科中最近公共祖先的定义为:“对于有根树 T 的两个结点 p、q,最近公共祖先表示为一个结点 x,满足 x 是 p、q 的祖先且 x 的深度尽可能大(一个节点也可以是它自己的祖先)。”
例如,给定如下二叉树: root = [3,5,1,6,2,0,8,null,null,7,4]
示例 1:
输入: root = [3,5,1,6,2,0,8,null,null,7,4], p = 5, q = 1
输出: 3
解释: 节点 5 和节点 1 的最近公共祖先是节点 3。
示例 2:
输入: root = [3,5,1,6,2,0,8,null,null,7,4], p = 5, q = 4
输出: 5
解释: 节点 5 和节点 4 的最近公共祖先是节点 5。因为根据定义最近公共祖先节点可以为节点本身。
说明:
- 所有节点的值都是唯一的。
- p、q 为不同节点且均存在于给定的二叉树中。
题目分析
不是搜索二叉树,那么就必须找到两个节点才算结束。
咕咕咕L1 (编辑过)2021-05-04
这题的递归理解实际没有那么简单,如果直接把函数理解成求以root为根的树中,pq的最近祖先节点其实是不准确的。 应该对该递归函数的定义进行扩充,这个函数实际上功能是:
- 如果在root为根的树中,同时具有pq两个节点,则返回最近祖先
- 如果在root为根中的树中,只有其中一个节点,则返回含有的那个节点
- 如果两个节点都不存在,则返回nullptr
经过对函数的定义扩充,才符合函数体中返回值的逻辑,而且也恰好能实现需要的功能。
初始解答:
参考上面的分析和解答
class Solution {
public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) {
if(root == null || root == p || root == q) return root;
TreeNode left = lowestCommonAncestor(root.left, p, q);
TreeNode right = lowestCommonAncestor(root.right, p, q);
if(left == null) return right;
if(right == null) return left;
return root;
}
}
执行结果:通过
显示详情 添加备注
执行用时:7 ms, 在所有 Java 提交中击败了99.98%的用户
内存消耗:39.9 MB, 在所有 Java 提交中击败了45.15%的用户
学习他人:
方法一:
…L1 (编辑过)2020-02-13
class Solution {
/**
* 二叉树的最近公共祖先
* 思路:
* 三种情况:
* 1、p q 一个在左子树 一个在右子树 那么当前节点即是最近公共祖先
* 2、p q 都在左子树
* 3、p q 都在右子树
* @param root
* @param p
* @param q
* @return
*/
public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) {
if (root == null) {
return null;
}
if (root == p || root == q) {
return root;
}
TreeNode left = lowestCommonAncestor(root.left, p, q);
TreeNode right = lowestCommonAncestor(root.right, p, q);
if (left != null && right != null) {
// p q 一个在左,一个在右
return root;
}
if (left != null) {
// p q 都在左子树
return left;
}
if (right != null) {
// p q 都在右子树
return right;
}
return null;
}
}
方法二:
(编辑过)2021-03-17
剑指offer书上的做法,时间效率不高,但也容易理解
class Solution {
public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) {
Deque<TreeNode> stackP = new ArrayDeque<>();
Deque<TreeNode> stackQ = new ArrayDeque<>();
getTrace(root,p,stackP); // 获取p和q的路径
getTrace(root,q,stackQ);
TreeNode ret = root;
while(!stackP.isEmpty()&&!stackQ.isEmpty()){
TreeNode nodeQ = stackQ.poll();
TreeNode nodeP = stackP.poll();
if(nodeP.val!=nodeQ.val) return ret;
ret = nodeP; //ret为最后一个相同的节点
}
return ret;
}
private boolean getTrace(TreeNode root , TreeNode node, Deque<TreeNode> stack){
stack.addLast(root);
boolean hasGet=false;
if(root.val == node.val) return true;
if(root.left!=null) hasGet = getTrace(root.left,node,stack);
if(!hasGet && root.right!=null&&!stack.isEmpty()) hasGet = getTrace(root.right,node,stack);
if(!hasGet&&!stack.isEmpty()) stack.removeLast();
return hasGet;
}
}
后续遍历,时间效率高,代码简洁优美,但感觉不是很好想_(¦3」∠)_
class Solution {
public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) {
if(root==null||root==p||root==q) return root;
TreeNode left = lowestCommonAncestor(root.left,p,q);
TreeNode right = lowestCommonAncestor(root.right,p,q);
if(left!=null && right!=null) return root;
if(left!=null) return left;
if(right!=null) return right;
return null;
}
}
方法三:
Brise 3 天前
class Solution {
public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) {
if(root==null){return null;}
if(root==p||root==q){return root;}
TreeNode left = lowestCommonAncestor(root.left,p,q);
TreeNode right = lowestCommonAncestor(root.right,p,q);
if(left ==null){
return right;
}else if(right==null){
return left;
}else{
return root;
}
}
}
方法四:
坏森生L1 2020-10-28
不用判空,p,q就是树内的节点;
class Solution {
public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) {
if(root == null)
return null;
if(p == root || q == root)
return root;
TreeNode left = lowestCommonAncestor(root.left,p,q);
TreeNode right = lowestCommonAncestor(root.right,p,q);
if(left != null && right != null)
return root;
return left == null ? right : left;
}
}
方法五
K神
作者:jyd
链接:https://leetcode-cn.com/problems/er-cha-shu-de-zui-jin-gong-gong-zu-xian-lcof/solution/mian-shi-ti-68-ii-er-cha-shu-de-zui-jin-gong-gon-7/
来源:力扣(LeetCode)
class Solution {
public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) {
if(root == null || root == p || root == q) return root;
TreeNode left = lowestCommonAncestor(root.left, p, q);
TreeNode right = lowestCommonAncestor(root.right, p, q);
if(left == null) return right;
if(right == null) return left;
return root;
}
}
展开写法
class Solution {
public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) {
if(root == null || root == p || root == q) return root;
TreeNode left = lowestCommonAncestor(root.left, p, q);
TreeNode right = lowestCommonAncestor(root.right, p, q);
if(left == null && right == null) return null; // 1.
if(left == null) return right; // 3.
if(right == null) return left; // 4.
return root; // 2. if(left != null and right != null)
}
}
总结
以上就是本题的内容和学习过程了,基本上有递归就有循环,断断续续两个月也过来了,后面就是复习,然后接着刷题保持手感了,大家加油啊。
完结撒花~
欢迎讨论,共同进步。