文章链接:24. 两两交换链表中的节点 、19.删除链表的倒数第N个节点、面试题 02.07. 链表相交、142.环形链表II、链表总结
视频链接:24. 两两交换链表中的节点 、19.删除链表的倒数第N个节点、142.环形链表II
题目链接:24. 两两交换链表中的节点 、19.删除链表的倒数第N个节点、面试题 02.07. 链表相交、142.环形链表II
思路:
24.两两交换链表中的节点
class Solution {
public:
ListNode* swapPairs(ListNode* head) {
ListNode* dummyHead = new ListNode(0); // 虚拟头节点
dummyHead->next = head;
ListNode* cur = dummyHead;
while(cur->next != NULL && cur->next->next != NULL){
ListNode* temp1 = cur->next;
ListNode* temp2 = cur->next->next->next;
cur->next = cur->next->next; // 1
cur->next->next = temp1; // 2
cur->next->next->next = temp2; // 3
cur = cur->next->next;
}
ListNode* result = dummyHead->next;
delete dummyHead; // 记得释放内存
return result;
}
};
19.删除链表的倒数第N个节点
这道题的关键思路就是怎么找出倒数第n个节点。
首先让fast走n + 1,然后fast和slow一起向前走,直达fast指向NULL,这时slow指向倒数第n + 1个节点;那么slow->next 就是倒数第n个节点。
class Solution {
public:
ListNode* removeNthFromEnd(ListNode* head, int n) {
ListNode* dummyHead = new ListNode(0); // 虚拟头节点
dummyHead->next = head;
ListNode* fast = dummyHead; // 快指针
ListNode* slow = dummyHead; // 慢指针
// 先让fast走n + 1;
// 然后fast和slow一起向前走,直达fast指向NULL; 这时slow指向倒数第n + 1个节点;
while(n-- && fast != NULL){
fast = fast->next;
}// fast走n步
fast = fast->next;// fast走n + 1步
while(fast != NULL){
fast = fast->next;
slow = slow->next;
}
slow->next = slow->next->next; // 删除第n个节点
ListNode* result = dummyHead->next;
delete dummyHead;
return result;
}
};
面试题 02.07. 链表相交
思路为将A和B尾部对齐,然后从同一位置开始遍历,若curA等于curB,则为交点;若一直没有,则二者没有交点。
class Solution {
public:
ListNode *getIntersectionNode(ListNode *headA, ListNode *headB) {
ListNode* curA = headA;
ListNode* curB = headB;
int lenA = 0, lenB = 0;
// 计算A的长度
while(curA != NULL){
lenA++;
curA = curA->next;
}
// 计算B的长度
while(curB != NULL){
lenB++;
curB = curB->next;
}
curA = headA; // 要将操作指针重新放回头节点处
curB = headB;
// 若B比A长,则要交换其长度和操作指针;即一定要保证A比B长
if(lenA < lenB){
swap(lenA, lenB);
swap(curA, curB);
}
// 将A和B的尾部对齐:即curA和cueB一起前进并同时到达NULL
int gap = lenA - lenB;
while(gap--){
curA = curA->next;
}
// 遍历A和B,直到找到交点
while(curA != NULL){
if(curA == curB){
return curA;
}
curA = curA->next;
curB = curB->next;
}
return NULL;
}
};
142.环形链表II
这道题有两个难点,一是如何判断一个链表是否有环;二是如何找到环的入口。
如何判断一个链表是否有环
定义两个指针,分别为快慢指针,若两指针相遇就是有环。
如何找到环的入口
所以,由上图得,index1与index2相遇的地方就是环入口。
class Solution {
public:
ListNode *detectCycle(ListNode *head) {
ListNode* fast = head;
ListNode* slow = head;
while(fast != NULL && fast->next != NULL){
fast = fast->next->next;
slow = slow->next;
if(fast == slow){ // 判断一个链表是否有环
ListNode* index1 = head;
ListNode* index2 = fast;
while(index1 != index2){ // 找环的入口
index1 = index1->next;
index2 = index2->next;
}
return index1;
}
}
return NULL;
}
};
困难:
24. 两两交换链表中的节点
问:为什么要用(两个)临时指针分别指向cur->next 和 cur->next->next->next ?
答:正如我在这道题的“思路”中画的图一样,cur->next = cur->next->next 该语句会将cur与cur->next之间的箭头断掉,如果不设立临时指针,那么等会需要用到的格子将没有办法可以找到。
问:为什么不能直接返回头节点?
答:头节点在执行完代码后已经改变了,而dummyHead->next才是真正改变后的头节点。
19.删除链表的倒数第N个节点
问:为什么删除第 n 个节点时,操作指针应该指向 n - 1 ?
答:因为删除第 n 个节点,就是把第 n - 1的节点的next指向第 n + 1 的节点,所以要将操作指针放在第 n - 1节点处。
问:怎么找到倒数第n个节点?
答:用双指针(快慢指针)。首先让fast走n + 1,然后fast和slow一起向前走,直达fast指向NULL,这时slow指向倒数第n + 1个节点;那么slow->next 就是倒数第n个节点。
面试题 02.07. 链表相交
无
142.环形链表II
问:为什么慢指针走不到一圈就被快指针追上?
答:因为慢指针走一圈,快指针肯定走了2圈,这两圈中肯定会遇到慢指针。
问:为什么只要判断fast != NULL 和 fast->next != NULL,不用判断fast->next->next != NULL ?
答:因为fast是走两步,若fast->next->next == NULL,那么走两步后fast就是原先的fast->next->next。
今日收获:
今天用3小时的时间,写了有关链表的四道题,相比较昨天,对链表及其节点的相关操作更加熟悉了。