4.141. 环形链表
给你一个链表的头节点
head
,判断链表中是否有环。如果链表中有某个节点,可以通过连续跟踪
next
指针再次到达,则链表中存在环。 为了表示给定链表中的环,评测系统内部使用整数pos
来表示链表尾连接到链表中的位置(索引从 0 开始)。注意:pos
不作为参数进行传递 。仅仅是为了标识链表的实际情况。如果链表中存在环 ,则返回
true
。 否则,返回false
。示例 1:
输入:head = [3,2,0,-4], pos = 1 输出:true 解释:链表中有一个环,其尾部连接到第二个节点。示例 2:
输入:head = [1,2], pos = 0 输出:true 解释:链表中有一个环,其尾部连接到第一个节点。示例 3:
输入:head = [1], pos = -1 输出:false 解释:链表中没有环。提示:
- 链表中节点的数目范围是
[0, 10^4]
-10^5 <= Node.val <= 10^5
pos
为-1
或者链表中的一个 有效索引 。进阶:你能用
O(1)
(即,常量)内存解决此问题吗?
思路:
太经典了,快慢指针,快指针如果能最终追上说明有环。本方法就是常量内存!
代码:
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode(int x) : val(x), next(NULL) {}
* };
*/
class Solution {
public:
bool hasCycle(ListNode *head) {
ListNode *p,*q;
if(!head || head->next==NULL)return false;
p=head;
q=head;
while(q->next!=NULL){
if(p==q){
return true;
}
else{
p=p->next;
q=q->next->next;
}
}
return false;
}
};
测试用例过了,但提交没通过,仔细瞅一下!
发现,直接q->next->next有点问题;修改一下:
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode(int x) : val(x), next(NULL) {}
* };
*/
class Solution {
public:
bool hasCycle(ListNode *head) {
ListNode *p,*q;
if(!head || head->next==NULL)return false;
p=head;
q=head;
while(q!=NULL){
q=q->next;
if(q!=NULL)//可能快指针会提前触底
q=q->next;
if(p==q){
return true;
}
else{
p=p->next;
}
}
return false;
}
};
AC!!!
5.142. 环形链表 II
给定一个链表的头节点
head
,返回链表开始入环的第一个节点。 如果链表无环,则返回null
。如果链表中有某个节点,可以通过连续跟踪
next
指针再次到达,则链表中存在环。 为了表示给定链表中的环,评测系统内部使用整数pos
来表示链表尾连接到链表中的位置(索引从 0 开始)。如果pos
是-1
,则在该链表中没有环。注意:pos
不作为参数进行传递,仅仅是为了标识链表的实际情况。不允许修改 链表。
示例 1:
输入:head = [3,2,0,-4], pos = 1 输出:返回索引为 1 的链表节点 解释:链表中有一个环,其尾部连接到第二个节点。示例 2:
输入:head = [1,2], pos = 0 输出:返回索引为 0 的链表节点 解释:链表中有一个环,其尾部连接到第一个节点。示例 3:
输入:head = [1], pos = -1 输出:返回 null 解释:链表中没有环。提示:
- 链表中节点的数目范围在范围
[0, 10^4]
内-10^5 <= Node.val <= 10^5
pos
的值为-1
或者链表中的一个有效索引进阶:你是否可以使用
O(1)
空间解决此题?
思路:
还是按照上一题的步骤,判断是否存在汇点;如果存在,则在找到汇点以后,另开一个指向头的指针,同时遍历,下一次两指针会面之时,就是汇点的位置。
第一次学的时候思路源自代码随想录代码随想录 (programmercarl.com)
里面详细介绍了,为什么会汇合!
代码:
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode(int x) : val(x), next(NULL) {}
* };
*/
class Solution {
public:
ListNode *detectCycle(ListNode *head) {
// ListNode *conjuction,*index;
if(head==NULL || head->next==NULL)return NULL;
ListNode *p=head;
ListNode *q=head;ListNode *index=head;
while(p!=NULL){
q=q->next;
if(q!=NULL){
q=q->next;
}
if(p==q){//当遇到汇合点时,新定义的扫描结点从头开始遍历,准备与交点指针相遇
// conjuction=p;
while(p!=index){
p=p->next;
index=index->next;
}
return p;
}
else{
p=p->next;
}
}
return NULL;//无环则返回NULL
}
};
说我超时了!!!
class Solution {
public:
ListNode *detectCycle(ListNode *head) {
ListNode* fast = head;
ListNode* slow = head;
while(fast != NULL && fast->next != NULL) {
slow = slow->next;
fast = fast->next->next;
// 快慢指针相遇,此时从head 和 相遇点,同时查找直至相遇
if (slow == fast) {
ListNode* index1 = fast;
ListNode* index2 = head;
while (index1 != index2) {
index1 = index1->next;
index2 = index2->next;
}
return index2; // 返回环的入口
}
}
return NULL;
}
};
6.21. 合并两个有序链表
将两个升序链表合并为一个新的 升序 链表并返回。新链表是通过拼接给定的两个链表的所有节点组成的。
示例 1:
输入:l1 = [1,2,4], l2 = [1,3,4] 输出:[1,1,2,3,4,4]示例 2:
输入:l1 = [], l2 = [] 输出:[]示例 3:
输入:l1 = [], l2 = [0] 输出:[0]提示:
- 两个链表的节点数目范围是
[0, 50]
-100 <= Node.val <= 100
L1
和 L2
均按 非递减顺序 排列
思路:
双指针,互相比较,较大者先入,然后往后移指针。
代码:
class Solution {
public:
ListNode* mergeTwoLists(ListNode* list1, ListNode* list2) {
ListNode* dum = new ListNode(0);
#用于保存头指针,因为哪个链表的第一个元素大不清楚,
#所以直接用一个虚拟头来做头指针!
ListNode* cur = dum;#添加头指针
while (list1 != nullptr && list2 != nullptr) {
if (list1->val < list2->val) {
cur->next = list1;
list1 = list1->next;
}
else {
cur->next = list2;
list2 = list2->next;
}
cur = cur->next;
}
cur->next = list1 != nullptr ? list1 : list2;
return dum->next;
}
};
还有递归解法: