24. 两两交换链表中的节点
重点
- 终止条件cur!=nullptr&&cur->next!=nullptr,cur!=nullptr是节点数是偶数,cur->next!=nullptr是节点数为奇数。
- 注意节点指向的交换顺序,以下有两种思路。
代码
- 自己的
class Solution {
public:
ListNode* swapPairs(ListNode* head) {
ListNode* dummyhead=new ListNode(0,head);
ListNode* pre=dummyhead;
ListNode* cur=head;
while(cur!=nullptr&&cur->next!=nullptr){
pre->next=pre->next->next;
cur->next=pre->next->next;
pre->next->next=cur;
pre=pre->next->next;
cur=pre->next;
}
return dummyhead->next;
}
};
- 代码随想录
这种方法需要cur指针的前后节点都要保存,不过代码可读性更高一些。
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个节点
重点
双指针的经典应用,如果要删除倒数第n个节点,让fast移动n步,然后让fast和slow同时移动,直到fast指向链表末尾。删掉slow所指向的节点就可以了。实现起来不难。
代码
class Solution {
public:
ListNode* removeNthFromEnd(ListNode* head, int n) {
ListNode* dummyhead=new ListNode(0,head);
ListNode* fast=dummyhead;
ListNode* slow=dummyhead;
while(n--){
fast=fast->next;
}
while(fast->next!=nullptr){
fast=fast->next;
slow=slow->next;
}
ListNode* tmp=slow->next;
slow->next=slow->next->next;
delete tmp;
return dummyhead->next;
}
};
160.链表相交
重点
- 交点不是数值相等,而是指针完全相等。
- 求出两链表的长度差,让curA移动到,和curB 末尾对齐的位置,如图,AB指针同时开始遍历,直到curA == curB,否则就没有交点。
- 注意B链表比A链表长的情况。
代码
class Solution {
public:
ListNode *getIntersectionNode(ListNode *headA, ListNode *headB) {
ListNode* curA=headA;
ListNode* curB=headB;
int lenghA=0;
int lenghB=0;
while(curA!=nullptr){
curA=curA->next;
lenghA++;
}
while(curB!=nullptr){
curB=curB->next;
lenghB++;
}
curA=headA;
curB=headB;
//让curA,lenghA都是最长链表的
if(lenghA<lenghB){
swap(lenghA,lenghB);
swap(curA,curB);
}
int lenghsub=lenghA-lenghB;
while(lenghsub--){
curA=curA->next;
}
while(curA!=nullptr){
curA=curA->next;
curB=curB->next;
if(curA==curB){
return curA;
}
}
return NULL;
}
};
142.环形链表II
重点
-
怎么确定有没有环
可以使用快慢指针法,分别定义 fast 和 slow 指针,从头结点出发,fast指针每次移动两个节点,slow指针每次移动一个节点,如果有环,fast和slow一定会在环里相遇,即fast==slow。
fast相对于slow是一个节点一个节点的靠近的,不会错过。
-
怎么找环的入口
fast和slow相遇时,slow在环里一定没有走完一圈(slow进来时,fast在环里某个位置,如果slow走完了一圈,那fast就走了两圈)。即相遇时slow走的路程时x+y。
相遇时,slow走了x+y,而fast指针走过x + y + n (y + z),n为fast指针在环内走了n圈才遇到slow指针。因为fast速度是slow两倍,所以:
(x + y) * 2 = x + y + n (y + z),
整理公式之后为:x = (n - 1) (y + z) + z
当 n为1的时候,公式就化解为 x = z,
也就是在相遇节点处,定义一个指针index1,在头结点处定一个指针index2。让index1和index2同时移动,每次移动一个节点, 那么他们相遇的地方就是 环形入口的节点。
n如果大于1,index1 指针在环里多转了(n-1)圈,然后再遇到index2,相遇点依然是环形的入口节点。
代码
class Solution {
public:
ListNode *detectCycle(ListNode *head) {
ListNode* fast=head;
ListNode* slow=head;
//while(fast->next!=NULL&&fast->next->next!=NULL)
//这种会在空链表的情况下错
while(fast != NULL && fast->next != NULL) {
fast=fast->next->next;
slow=slow->next;
if(fast==slow){
ListNode* index1=head;
ListNode* index2=slow;
while(index1!=index2){
index1=index1->next;
index2=index2->next;
}
return index1;
}
}
return NULL;
}
};