目录
24. 两两交换链表中的节点
题目链接
(1)文字讲解:https://programmercarl.com/0024.两两交换链表中的节点.html#思路
(2)视频讲解:
(3)题目链接:https://leetcode.cn/problems/swap-nodes-in-pairs/
看到题解之前的想法
一开始理解错题目的意思了,以为需要先转12,再转23,再34,但是本题只要求转12后转34,再56,就可以了。
看到题解之后的想法
1.做链表的题目一定要清楚每个步骤的先后顺序,先后修改哪个节点的next;然后如果中途你有因为改变next而失去联系的某些节点,用tmp去记录就好。
2.这一题其实没有定死改变的先后顺序,我自己写的虽然和题解有出入但是也是对的。
(1)我写的:
(2)题解写的:
本题难点
1.理清楚改变next的前后关系
2.确定用tmp临时保存哪个节点
代码
我写的:
/**
* 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) {}
* };
*/
// struct ListNode{
// int val;
// ListNode *next;
// ListNode(): val(0), next(nullptr){}
// ListNode(int val): val(0), next(nullptr){}
// ListNode(int val, ListNode* next): val(val), next(next){}
// };
class Solution {
public:
ListNode* swapPairs(ListNode* head) {
ListNode *dummyhead = new ListNode(0, head);
ListNode *cur = dummyhead;
ListNode *tmp = NULL;
while(cur->next && cur->next->next){
tmp = cur->next;
cur->next = cur->next->next;
tmp->next = tmp->next->next;
cur->next->next = tmp;
cur = tmp;
}
return dummyhead->next;
}
};
题解写的:
class Solution {
public:
ListNode* swapPairs(ListNode* head) {
ListNode* dummyHead = new ListNode(0); // 设置一个虚拟头结点
dummyHead->next = head; // 将虚拟头结点指向head,这样方便后面做删除操作
ListNode* cur = dummyHead;
while(cur->next != nullptr && cur->next->next != nullptr) {
ListNode* tmp = cur->next; // 记录临时节点
ListNode* tmp1 = cur->next->next->next; // 记录临时节点
cur->next = cur->next->next; // 步骤一
cur->next->next = tmp; // 步骤二
cur->next->next->next = tmp1; // 步骤三
cur = cur->next->next; // cur移动两位,准备下一轮交换
}
return dummyHead->next;
}
};
19.删除链表的倒数第N个节点
题目链接
(1)文字讲解:https://programmercarl.com/0019.删除链表的倒数第N个节点.html#思路
(2)视频讲解:
(3)题目链接:https://leetcode.cn/problems/remove-nth-node-from-end-of-list/description/
看到题解之前的想法
不知道怎么做,因为他是要删除倒数的第n个节点,而链表的长度是不知道的,如果正常来说,先要遍历一遍链表得到长度,然后返回去n个。但是这个题目要求一趟扫描实现。
看到题解之后的想法
1.双指针,fast指针先走n步,然后slow和fast一起动,直到fast指向最后一个节点,这时候fast已经走了链表长度l的步数,slow走了l-n步,也就是说现在slow就指向了倒数第n个节点。
2.但是为了方便删除操作,fast需要走n+1步,因为这样slow就会走到被删除的节点的前一个节点。
3.加一个虚拟头节点后,相当于链表长度变长了,fast和slow相对关系不变,只是判断条件从fast到最后一个节点变成fast指向空(相当于l+1)。
4.如果你的判断条件是while(fast->next),那么相当于你缩短了fast走的长度,那么n不应该加一,就可以让slow指向被删除节点的前一个节点。
本题难点
1.双指针
2.想明白while判断条件和n是否++。
代码
/**
* 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) {}
* };
*/
// struct ListNode{
// int val;
// ListNode *next;
// ListNode(): val(0), next(nullptr){}
// ListNode(int val): val(val), next(nullptr){}
// ListNode(int val, ListNode* next): val(val), next(next){}
// }
class Solution {
public:
ListNode* removeNthFromEnd(ListNode* head, int n) {
ListNode *dummyhead = new ListNode(0, head);
ListNode *slow = dummyhead;
ListNode *fast = dummyhead;
n++;
while(n--){
fast = fast->next;
}
// while(fast->next)
while(fast){
slow = slow->next;
fast = fast->next;
}
ListNode *tmp = slow->next;
slow->next = slow->next->next;
delete tmp;
return dummyhead->next;
}
};
面试题 02.07. 链表相交
题目链接
(1)文字讲解:https://programmercarl.com/面试题02.07.链表相交.html
(2)视频讲解:
(3)题目链接:https://leetcode.cn/problems/intersection-of-two-linked-lists-lcci/description/
看到题解之前的想法
不知道怎么做,因为直观的办法就是暴力,对于每一个A链表中的节点,都遍历B链表中的节点看一下是否有相等的。
看到题解之后的想法
1.首先求出A,B两个链表的长度
2.然后让A,B两个链表在尾部对齐。如果A和B有相交的地方,说明A和B的尾部一定是对齐的。从短的链表的开头,以及长的链表的和短链表的对齐处开始比较,一旦相等,就是答案了。
本题难点
1.正着找相交点因为长度不同所以不好找,因此反着找。
2.节点相等是地址一致,不是val相等。
代码
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode(int x) : val(x), next(NULL) {}
* };
*/
class Solution {
public:
ListNode *getIntersectionNode(ListNode *headA, ListNode *headB) {
int sizeA = 0, sizeB = 0, offset = 0, result = 0;
ListNode *curA = headA;
ListNode *curB = headB;
while(curA){
curA = curA->next;
sizeA++;
}
while(curB){
curB = curB->next;
sizeB++;
}
curA = headA;
curB = headB;
if(sizeA > sizeB){
offset = sizeA - sizeB;
while(offset--){
curA = curA->next;
}
}else{
offset = sizeB - sizeA;
while(offset--){
curB = curB->next;
}
}
// result = offset;
bool flag = 0;
while(curA && curB){
if (curA == curB){
flag = 1;
break;
}
curA = curA->next;
curB = curB->next;
}
if(flag){
return curA;
}else{
return NULL;
}
}
};
142.环形链表II
题目链接
(1)文字讲解:https://programmercarl.com/0142.环形链表II.html#思路
(2)视频讲解:
(3)题目链接:https://leetcode.cn/problems/linked-list-cycle-ii/description/
看到题解之前的想法
只知道用快慢指针判断链表是否有环,但是不知道怎么给出环开始的节点。
看到题解之后的想法
1.双指针,fast指针每次走两步,slow指针每次走一步,如果slow和fast能够相遇,说明有环。
2.如果把slow和fast指针的相遇轨迹画一个图,那就如下:
slow指针的步数:x+y
fast指针的步数:x+y+n*(z+y)
为什么不可能是slow也转了m圈之后才遇到fast呢?因为假设slow进入环的时候,fast刚刚从入口走过一步(这是两个指针在环中相差最大的时候了),那么fast每次走两步,slow每次走一步,fast走完两个环,slow刚好走完一个环,他们在入口相遇,这是相差最大的情况,如果是其他的情况,他们会更早相遇,也就是slow不会走超过一圈
fast的步数是slow的两倍,也就是2*(x+y) = x+y+n*(z+y)
整理可得:x = (n - 1) (y + z) + z
如果n=1,那么x=z,也就是让一个节点从head开始走,一个节点从相遇点开始走,他们两个节点相遇的时候就是环的入口
如果n>1,那也没事,反正他俩相遇的时候就是环的入口。
3.我写的时候,思路是先判断是否有环,所以先写了一个while循环,如果相遇,break,然后从fast是否为空判断是否相遇了。
while(fast){
fast = fast->next->next;
slow = slow->next;
if(fast == slow){
break;
}
}
if(fast == NULL){
return NULL;
}
但是这样写是有问题的,因为当链表为奇数个的时候,fast每次走两步,到末尾的一步的时候,fast = fast->next->next;会报错。所以在while里面要加一个fast->next!=NULL。加了这个之后,下面的if也要加,因为这两种null都说明这个链表是有尽头的,不是环。
while(fast && fast->next){
fast = fast->next->next;
slow = slow->next;
if(fast == slow){
break;
}
}
if(fast == NULL or fast->next == NULL){
return NULL;
}
本题难点
1.双指针判断时候有环
2.根据图和fast与slow的关系,列出公式得出x和z的关系,从而算出环的进入点
代码
我写的:
/**
* 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 NULL;
if (head->next == NULL) return NULL;
ListNode *slow = head;
ListNode *fast = head;
while(fast && fast->next){
fast = fast->next->next;
slow = slow->next;
if(fast == slow){
break;
}
}
if(fast == NULL or fast->next == NULL){
return NULL;
}
ListNode *cur = head;
while(cur){
if(slow == cur){
break;
}
cur = cur->next;
slow = slow->next;
}
return cur;
}
};
题解写的:
/**
* 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 *slow = head;
ListNode *fast = head;
while(fast && fast->next){
fast = fast->next->next;
slow = slow->next;
if(fast == slow){
ListNode *node1 = head;
ListNode *node2 = fast;
while(node1 != node2){
node1 = node1->next;
node2 = node2->next;
}
return node1;
}
}
return NULL;
}
};