24. 两两交换链表中的节点
思路
建议使用虚拟头结点,这样会方便很多,要不然每次针对头结点(没有前一个指针指向头结点),还要单独处理。
接下来就是交换相邻两个元素了,此时一定要画图,不画图,操作多个指针很容易乱,而且要操作的先后顺序
个人思路:
画图一步步模拟
交换1节点和2节点:
创建虚拟头节点(ListNode* V_head =new ListNode(0);
V_head->next = head;)
设置当前节点指向虚拟头节点(ListNode* cur =V_head;)
当 当前节点的下一节点及下下节点不为空则继续循环(头节点设为0节点)
保存1节点(ListNode* tmp =cur->next;)
保存3节点(ListNode* tmp1 = cur->next->next->next;)
节点0指向节点2(cur->next = cur->next->next;)
节点2指向节点1( cur->next->next =tmp;)
节点1指向节点3(tmp->next = tmp1;)
交换完成 cur向前移动2位(cur = cur->next->next;)
返回头节点(return V_head->next;)
class Solution {
public:
ListNode* swapPairs(ListNode* head) {
ListNode* V_head =new ListNode(0);//设置一个虚拟头节点
V_head->next = head;
ListNode* cur =V_head;
while(cur->next !=nullptr && cur->next->next !=nullptr){
//这里交换节点1和节点2
ListNode* tmp =cur->next;//保存第一个节点
ListNode* tmp1 = cur->next->next->next; //保存第三个节点
cur->next = cur->next->next;//头节点指向节点2
cur->next->next =tmp;//节点2指向节点1
tmp->next = tmp1;//节点1指向节点3
//往后移动链表(cur移动两位)
cur = cur->next->next;
}
//返回头节点
return V_head->next;
}
};
2024.5.14 二刷
代码思路
交换两两相邻的元素
设置一个虚拟头节点 设置当前节点指针(ListNode* V_head =new ListNode(0);//设置一 个虚拟头节点 V_head->next = head; ListNode* cur =V_head;)
当当前节点的下一节点及下下节点不为空(要交换的两个节点不为空)(while(cur->next !=nullptr && cur->next->next !=nullptr))
首先保存第一个节点与第三个节点(ListNode* tmp =cur->next;//保存第一个节点 ListNode* tmp1 = cur->next->next->next; //保存第三个节点)
交换节点(cur->next = cur->next->next;//头节点指向节点2 cur->next->next =tmp;//节点2指向节点1 tmp->next = tmp1;//节点1指向节点3)
交换完往下移动2步 交换下一相邻节点(cur = cur->next->next;)
19. 删除链表的倒数第 N 个结点
思路
双指针的经典应用,如果要删除倒数第n个节点,让fast移动n步,然后让fast和slow同时移动,直到fast指向链表末尾。删掉slow所指向的节点就可以了。
-
定义fast指针和slow指针,初始值为虚拟头结点,如图:
fast首先走n + 1步 ,为什么是n+1呢,因为只有这样同时移动的时候slow才能指向删除节点的上一个节点(方便做删除操作),如图:
fast和slow同时移动,直到fast指向末尾,如题:
删除slow指向的下一个节点,如图:
快慢指针
快慢指针永远相差n 当快指针移动到最后 为空时 慢指针就指向倒数第n个节点
创建虚拟头节点(ListNode* V_head =new ListNode(0);//虚拟头节点
V_head->next = head;)
创建快慢指针
注意治理走到最后 fast跟slow相差n 所以当fast走到末尾时指向空指针,此时slow对应的就是倒数的第n个数了
class Solution {
public:
ListNode* removeNthFromEnd(ListNode* head, int n) {
ListNode* V_head =new ListNode(0);//虚拟头节点
V_head->next = head;
//快慢指针
ListNode* fast =V_head;
ListNode* slow =V_head;
//先让fast 走n+1步找到第n个节点 (如果n大于链表长度 则fast为空)
while(n-- && fast!= NULL){
fast = fast->next;
}
fast =fast->next;//n+1步
//当fast走到第n+1,开始移动slow到n个节点的上一个节点;
while(fast!=NULL){
fast = fast->next;
slow =slow->next;
}
slow->next =slow->next->next;//删除节点
return V_head->next;
}
};
160. 相交链表
思路(o(n+m))
简单来说,就是求两个链表交点节点的指针。 这里同学们要注意,交点不是数值相等,而是指针相等。
为了方便举例,假设节点元素数值相等,则节点指针相等。
看如下两个链表,目前curA指向链表A的头结点,curB指向链表B的头结点:
我们求出两个链表的长度,并求出两个链表长度的差值,然后让curA移动到,和curB 末尾对齐的位置,如图:
此时我们就可以比较curA和curB是否相同,如果不相同,同时向后移动curA和curB,如果遇到curA == curB,则找到交点。
否则循环退出返回空指针。
ListNode* curA = headA;
ListNode* curB = headB;
int lenA = 0, lenB = 0;
while (curA != NULL) { // 求链表A的长度
lenA++;
curA = curA->next;
}
while (curB != NULL) { // 求链表B的长度
lenB++;
curB = curB->next;
}
curA = headA;
curB = headB;
// 让curA为最长链表的头,lenA为其长度
if (lenB > lenA) {
swap (lenA, lenB);
swap (curA, curB);
}
// 求长度差
int gap = lenA - lenB;
// 让curA和curB在同一起点上(末尾位置对齐)
while (gap--) {
curA = curA->next;
}
// 遍历curA 和 curB,遇到相同则直接返回
while (curA != NULL) {
if (curA == curB) {
return curA;
}
curA = curA->next;
curB = curB->next;
}
return NULL;
142. 环形链表 II
思路
判断链表是否有环
可以使用快慢指针法,分别定义 fast 和 slow 指针,从头结点出发,fast指针每次移动两个节点,slow指针每次移动一个节点,如果 fast 和 slow指针在途中相遇 ,说明这个链表有环。
要注意 在进入环后只会继续在环里面转圈圈,此时fast 相对于 slow 是做步进为1的靠近,一个不动(slow),一个以1的速度向前步进(fast) 这样子总会相遇的
龟兔赛跑
1.设置快慢指针指向头节点()
ListNode* fast = head; ListNode* slow = head;
2.当快指针及快指针节点的下一节点不为空进入循环(while(fast != NULL && fast->next != NULL)
快指针走两步慢指针走一步()
slow = slow->next; fast = fast->next->next;
3.当快指针与慢指针相遇,设置初始指针及相遇点指针
f (slow == fast) { ListNode* index1 = fast; ListNode* index2 = head;
4.两个指针同时向前移动,移动到相遇位置即为入口
while (index1 != index2) { index1 = index1->next; index2 = index2->next; } return index2; // 返回环的入口
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;
}
};