142. 环形链表 II

题目

给定一个链表,返回链表开始入环的第一个节点。 如果链表无环,则返回 null

为了表示给定链表中的环,我们使用整数 pos 来表示链表尾连接到链表中的位置(索引从 0 开始)。 如果 pos-1,则在该链表中没有环。注意,pos 仅仅是用于标识环的情况,并不会作为参数传递到函数中。

说明:不允许修改给定的链表。

进阶:

  • 你是否可以使用 O(1) 空间解决此题?

示例 1:

输入:head = [3,2,0,-4], pos = 1
输出:返回索引为 1 的链表节点
解释:链表中有一个环,其尾部连接到第二个节点。

示例 2:

输入:head = [1,2], pos = 0
输出:返回索引为 0 的链表节点
解释:链表中有一个环,其尾部连接到第一个节点。

示例 3:

输入:head = [1], pos = -1
输出:返回 null
解释:链表中没有环。

提示:

  • 链表中节点的数目范围在范围 [0, 104]
  • -105 <= Node.val <= 105
  • pos 的值为 -1 或者链表中的一个有效索引

思路

就是暴力
1.先通过两个从头开始的指针,一个一次走一步,一个一次走两步,看两者能不能相遇,以此来确定有没有环,如果没有环直接返回NULL,有环则记录下两个指针相等的位置n1.
2.如果有环,那么环的头节点一定在head到n1之间,那么只需要再head和n1之间便利,从head往后一个一个开始,看看循环1~2圈只能能不能回到起始节点,如果可以那么证明事头节点,如果不行就往后。直到找到。

代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
/**
* 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) {
if(head==NULL) return head;
ListNode* n1,*n2;
n1=head;
n2=head->next;
// if(n1==NULL||n2==NULL||n2->next==NULL) return NULL;
while(n1!=n2){
// printf("n1:%d n2:%d\n",n1->val,n2->val);
if(n2==NULL||n2->next==NULL) return NULL;
n2=n2->next->next;
n1=n1->next;
};
//再head和n1之间存在环,从一个节点开始,到n1结束
ListNode* h=head;
//h肯定在h~n1之间,看h到n1之前的节点是不是一样,前面有就在前面,前面没有就是n1
while(h!=n1){
bool finded=false;
ListNode* ch=h->next;
while(ch!=h){
if(ch==n1){
if(finded){
break;
}else{
finded=true;
}
}
ch=ch->next;
}
if(ch==h) return h;
else h=h->next;
}
return h;
}
};

92. 反转链表 II

题目

给你单链表的头指针 head 和两个整数 leftright ,其中 left <= right 。请你反转从位置 left 到位置 right 的链表节点,返回 反转后的链表

示例 1:

输入:head = [1,2,3,4,5], left = 2, right = 4
输出:[1,4,3,2,5]

示例 2:

输入:head = [5], left = 1, right = 1
输出:[5]

提示:

  • 链表中节点数目为 n
  • 1 <= n <= 500
  • -500 <= Node.val <= 500
  • 1 <= left <= right <= n

思路

首先找到第一个开始的反转节点
反转一个链表须要三个半节点:反转链表的第一个(算半个)pre->next,反转链表过程中的第一个head,反转链表过程中未反转部分的第一个nxt,反转链表未反转部分的第二个aft。
每次让nxt的next只想head,之后head变为nxt,这样即实现了一个节点反转到头节点的过程。之后nxt转为未反转部分的第一个,也即原来的aft,aft后移。
全部移动完成后,须要将原来反转链表的第一个pre->next的next设置为nxt,以此实现反转后的尾节点与后续节点链接。之后pre的next节点设置为反转后的第一个节点head。返回第一个节点即可。
为了方便返回第一个节点,这里在头节点前插入新节点。

代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode(int x) : val(x), next(NULL) {}
* };
*/
class Solution {
public:
ListNode* reverseBetween(ListNode* head, int m, int n) {
if(m==n) return head;
int cnt = 1;
ListNode* pre = new ListNode(0);
pre->next = head;
ListNode* h = pre;
while(cnt<m){
pre=head;
head=head->next;
cnt++;
}
ListNode* nxt=head->next,*aft=head->next->next,*lst = head;
while(cnt<n){
nxt->next = head;
head=nxt;
nxt=aft;
if(aft)aft=aft->next;
cnt++;
}
pre->next->next = nxt;
pre->next = head;
return h->next;
}
};