24. 两两交换链表中的节点 19.删除链表的倒数第N个节点 面试题 02.07. 链表相交 142.环形链表II
24. 两两交换链表中的节点
实现思路

- 定义一个虚拟头结点 head_dummp,初始的 next 指针指向链表的头结点 head。
- 定义一个指针变量 p,初始指向虚拟头结点 head_dummp。
- 判断 p 指向的节点是否有下一个节点且下一个节点是否有下一个节点,如果没有则退出循环。
- 定义两个指针变量 temp1 和 temp2,分别指向 p 指向的节点的下一个节点和 p 指向的节点的下一个节点的下一个节点的下一个节点。
- 交换 p 指向的节点的下一个节点和 p 指向的节点的下一个节点的下一个节点。具体操作是:
- 将 p 指向的节点的 next 指针指向 p 指向的节点的下一个节点的下一个节点。
- 将 p 指向的节点的下一个节点的下一个节点的 next 指针指向 p 指向的节点的下一个节点。
- 将 p 指向的节点的下一个节点的 next 指针指向 temp2。
- 将 p 指向的节点的 next 指针指向 p 指向的节点的下一个节点的下一个节点。
- 重复步骤 3-6,直到 p 指向的节点没有下一个节点或下一个节点没有下一个节点。
while (p->next != nullptr && p->next->next != nullptr)
每次循环的条件是 p 指向的节点有下一个节点且下一个节点有下一个节点。
代码实现
/**
* 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) {}
* };
*/
class Solution {
public:
ListNode* swapPairs(ListNode* head) {
ListNode* head_dummp = new ListNode();
head_dummp->next = head;
ListNode*p = head_dummp;
ListNode*temp1 = nullptr;
ListNode*temp2 = nullptr;
while(p->next!=nullptr && p->next->next!=nullptr)
{
temp1 = p->next;
temp2 = p->next->next->next;
p->next = p->next->next;
p->next->next = temp1;
temp1->next = temp2;
p = p->next->next;
}
return head_dummp->next;
}
};
19.删除链表的倒数第N个节点
实现思路
本题使用双指针的方法即可,快指针和慢指针相隔n+1个结点,移动速度都为1,这样快指针第一次移动到null的时候,慢指针刚好指向待删除结点的前驱结点q,此时q指向q->next->next即可。注意,力扣上面如果没有特别说明,head结点均是存储数据的,所以可以使用虚拟头节点来解决这个问题。
代码实现
/**
* 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) {}
* };
*/
class Solution {
public:
ListNode* removeNthFromEnd(ListNode* head, int n) {
ListNode* dummy_head = new ListNode();
dummy_head->next = head;
// 初始化慢指针
ListNode* q = dummy_head;
// 初始化快指针
ListNode* p = dummy_head;
n+=1;
while(n--)
p = p->next;
// 查找
while(p!=nullptr)
{
p = p->next;
q = q->next;
}
q->next = q->next->next;
return dummy_head->next;
}
};
面试题 02.07. 链表相交
实现思路

本题解决方法也是使用双指针的解法,如上图所示,我们分别从a1和b1开始遍历,当遍历完c3时,再接着遍历另外一个链表。
// 第一次循环 无相同
headA:a1+a2+c1+c2+c3+b1+b2+b3
headB:b1+b2+b3+c1+c2+c3+a1+a2
// 第二次循环 c1 相同
headA:c1+c2+c3+a1+a2
headB:c1+c2+c3+b1+b2+b3
⬆
当循环headA循环b3结束后让指针指向
代码实现
/**
* 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) {
if(headA==nullptr || headB==nullptr)
return nullptr;
ListNode* p = headA;
ListNode* q = headB;
while(p!=q)
{
if(p==nullptr)
p = headB;
else
p = p->next;
if(q==nullptr)
q = headA;
else
q = q->next;
}
if(p==q && p==nullptr)
return nullptr;
else
return p;
}
};
链表相交 142.环形链表II
实现思路
采用floyd算法实现。我们使用 Floyd 算法来检测链表是否有环。使用两个指针 slow 和 fast,初始都指向链表的头节点 head,然后,我们在链表上进行遍历,每次让 slow 指针向前移动一个节点,让 fast 指针向前移动两个节点。当两个指针相遇时,我们就可以确定链表有环。
如果链表无环,则 fast 指针会在遍历结束时变为 nullptr。如果链表有环,我们就使用两个指针(从头开始遍历的指针和从相遇点出发的指针)同时遍历,直到再次相遇。这时,这个相遇的节点即为链表开始入环的第一个节点。
代码实现
/**
* 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) {
slow = slow->next;
fast = fast->next->next;
// 如果链表有环,则 slow 和 fast 会在环内相遇
if (slow == fast) {
// 从头开始遍历,并用另一个指针同时从相遇点出发
// 当两个指针再次相遇时,即为链表开始入环的第一个节点
ListNode* ptr1 = head;
ListNode* ptr2 = fast;
while (ptr1 != ptr2) {
ptr1 = ptr1->next;
ptr2 = ptr2->next;
}
return ptr1;
}
}
// 如果 fast 为 nullptr,则说明链表无环
return nullptr;
}
};

浙公网安备 33010602011771号