题一:二叉搜索树的最近公共祖先
给定一个二叉搜索树, 找到该树中两个指定节点的最近公共祖先。
百度百科中最近公共祖先的定义为:“对于有根树 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 为不同节点且均存在于给定的二叉搜索树中。
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/lowest-common-ancestor-of-a-binary-search-tree
/**
* Definition for a binary tree node.
* struct TreeNode {
* int val;
* TreeNode *left;
* TreeNode *right;
* TreeNode(int x) : val(x), left(NULL), right(NULL) {}
* };
*/
class Solution {
public:
TreeNode* lowestCommonAncestor(TreeNode* root, TreeNode* p, TreeNode* q) {
//三种情况,第一:p,q都在右子树上,去右子树上找祖先
//第二:p,q都在左子树上,去左子树上找祖先
//第三:当p,q一个在左子树上,一个在右子树上,则返回根节点
if(p->val>root->val&&q->val>root->val)
return lowestCommonAncestor(root->right,p,q);
else if(p->val<root->val&&q->val<root->val)
return lowestCommonAncestor(root->left,p,q);
else
return root;
}
};
题二:剑指 Offer 22. 链表中倒数第k个节点
输入一个链表,输出该链表中倒数第k个节点。为了符合大多数人的习惯,本题从1开始计数,即链表的尾节点是倒数第1个节点。
例如,一个链表有 6 个节点,从头节点开始,它们的值依次是 1、2、3、4、5、6。这个链表的倒数第 3 个节点是值为 4 的节点。
示例:
给定一个链表: 1->2->3->4->5, 和 k = 2.
返回链表 4->5.
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/lian-biao-zhong-dao-shu-di-kge-jie-dian-lcof
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode(int x) : val(x), next(NULL) {}
* };
*/
class Solution {
public:
ListNode* getKthFromEnd(ListNode* head, int k) {
//利用快慢指针,先让快指针向前移动k个结点
//再将快慢指针同时移动,当快指针指向NULL时,慢指针所指位置即为倒数第k个结点
if(head==NULL)
return nullptr;
ListNode *quick,*slow;
quick=slow=head;
for(int i=0;i<k;i++){
quick=quick->next;
}
while(quick!=NULL){
quick=quick->next;
slow=slow->next;
}
return slow;
}
};
题三:剑指 Offer II 021. 删除链表的倒数第 n 个结点
给定一个链表,删除链表的倒数第 n 个结点,并且返回链表的头结点。
示例 1:
输入:head = [1,2,3,4,5], n = 2
输出:[1,2,3,5]
示例 2:
输入:head = [1], n = 1
输出:[]
示例 3:
输入:head = [1,2], n = 1
输出:[1]
提示:
链表中结点的数目为 sz
1 <= sz <= 30
0 <= Node.val <= 100
1 <= n <= sz
进阶:能尝试使用一趟扫描实现吗?
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/SLwz0R
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode() : val(0), next(nullptr) {}
* ListNode(int x) : val(x), next(nullptr) {}
* ListNode(int x, ListNode *next) : val(x), next(next) {}
* };
*/
class Solution {
public:
ListNode* removeNthFromEnd(ListNode* head, int n) {
//删除倒数第n个元素,必须知道其前驱结点的位置
//利用快慢指针,让快指针先移动n+1次
//再同属移动快慢指针,直至快指针指向空
//在大多数单链表的操作中,都可以考虑使用虚拟头结点
//使用虚拟空指针,防止出现空指针的情况
ListNode *dummy=new ListNode(-1);
dummy->next=head;
ListNode *quick,*slow;
quick=slow=dummy;
for(int i=0;i<=n;i++){
quick=quick->next;
}
while(quick!=NULL){
quick=quick->next;
slow=slow->next;
}
slow->next=slow->next->next;
return dummy->next;
}
};