24.两两交换链表的节点
给你一个链表,两两交换其中相邻的节点,并返回交换后链表的头节点。你必须在不修改节点内部的值的情况下完成本题(即,只能进行节点交换)。
代码实现
class Solution {
public:
ListNode* swapPairs(ListNode* head) {
ListNode* tmp1, *tmp2;
ListNode* dhead = new ListNode(0,head);
ListNode* cur = dhead;
while(cur->next&&cur->next->next)
{
tmp1 = cur->next;
tmp2 = cur->next->next->next;
cur->next = cur->next->next;
cur->next->next = tmp1;
cur->next->next->next = tmp2;
cur = cur->next->next;
}
return dhead->next;
}
};
感悟
为什么需要虚拟头结点:会方便很多,要不然每次针对头结点(没有前一个指针指向头结点),还要单独处理。
以第一次循环举例,为什么需要保存第一个和第三个节点:因为要将第二个改为新的头节点,同时会改变该节点的next。
19.删除链表的倒数第N个节点
给你一个链表,删除链表的倒数第 n
个结点,并且返回链表的头结点。
思路
运用快慢指针,如果要求倒数第n个,那么先让fast指针走n次,然后fast,slow指针一起走,最终slow指针停下的地方就是倒数第n个节点
代码实现
class Solution {
public:
ListNode* removeNthFromEnd(ListNode* head, int n) {
if(head->next== nullptr) return nullptr;
ListNode* dhead = new ListNode(0,head);
ListNode* fast = dhead;
ListNode* slow = dhead;
while(n--)
{
fast = fast->next;
}
while(fast->next)
{
fast = fast->next;
slow = slow->next;
}
slow->next = slow->next->next;
return dhead->next;
}
};
面试题02.07链表相交
思路
设链表A长度为a,链表B长度为b,设置两个指针pa,pb分别等于headA,headB。
让pa走一遍链表A,再走一遍链表B,那么走过的长度是a+b,让 pb走一遍链表B,再走一遍链表A,那么走过的长度就是b+a,此时可以理解为两个链表末尾对齐,然后就可以找到相同节点。
代码实现
class Solution {
public:
ListNode *getIntersectionNode(ListNode *headA, ListNode *headB) {
if(headA== nullptr||headB== nullptr)
return nullptr;
ListNode* pa = headA, *pb = headB;
while(pa!=pb)
{
pa = pa==nullptr?headB:pa->next;
pb = pb== nullptr?headA:pb->next;
}
return pa;
}
};
142.环形链表II
思路
设环之前的长度为a,环的长度为b。
使用快慢指针,fast,slow指针第一次相遇时f = 2s,f = s+nb。
推导出f = 2nb,s=nb。
此时应该,让fast重新回到头节点,然后fast,slow同时走,第二次相遇时,fast,slow走的长度都是a,所以两个指针此时在环的头相遇。
代码实现
class Solution {
public:
ListNode *detectCycle(ListNode *head) {
ListNode* fast= head;
ListNode* slow = head;
while(fast!= nullptr&&fast->next!= nullptr)
{
fast = fast->next->next;
slow = slow ->next;
if(fast==slow)
{
fast = head;
while(fast!=slow)
{
fast = fast->next;
slow = slow->next;
}
return fast;
}
}
return nullptr;
}
};