前言
链表+双指针:双指针就是用来处理题目问题的,无论是判断链表相交还是带环,归根到底我们学的还是数学知识,巧妙用数学知识让我们解题目的速度会更快。代码更优雅
题目链接
19. 删除链表的倒数第 N 个结点 - 力扣(LeetCode)
面试题 02.07. 链表相交 - 力扣(LeetCode)
一、两两交换链表中的节点
思路: 定义一个伪头结点,然后定义快慢指针,快指针指向头,慢指针指向伪头,定义两个临时变量去指向交换的节点,和下一个迭代的节点。判断条件是快指针及其下一个对象不为空。
最后执行交换操作和更新操作。
交换操作分为三步:
①伪头指向2
②2指向1
③1指向3
更新操作:
①慢指针指向2
②快指针指向3
//迭代操作,三步走,交换,
ListNode* swapPairs1(ListNode* head) {
ListNode* newHead=new ListNode(0,head);//保留伪头
ListNode* fast=head;
ListNode* slow=newHead;
while(fast&&fast->next){
ListNode* tmp1=fast->next;//交换的下一个
ListNode* tmp2=tmp1->next;//下一组的第一个
slow->next=tmp1;//交换第二个,指向哨兵下一个,哨兵->2
tmp1->next=fast;//交换的下一个,等于原先的2->1
fast->next=tmp2;//指向下一组的第一个1->4
//更新操作
slow=fast;//进入新的交换的哨兵 1
fast=tmp2;//下一组 4
}
return newHead->next;
}
//递归的思路
ListNode* swapPairs(ListNode* head) {
if (head == nullptr || head->next == nullptr) {
return head;
}
ListNode* node1 = head;
ListNode* node2 = head->next;
ListNode* node3 = node2->next;
node1->next = swapPairs(node3); // 1 指向递归返回的链表头
node2->next = node1; // 2 指向 1
return node2; // 返回交换后的链表头节点
}
二、删除倒数第N个节点
思路:正向简化,寻找到需要删除的结点,直接亏快指针先走N步,然后快慢一起走,就符合题目说的,倒数的意思。
ListNode* removeNthFromEnd(ListNode* head, int n) {
if(head==nullptr||n<=0) return nullptr;
ListNode* newHead=new ListNode(0,head);
ListNode* fast=head;
ListNode* slow=newHead;
while(n--)fast=fast->next;//快先走
while(fast){//快慢一起走
fast=fast->next;
slow=slow->next;
}//执行删除逻辑
ListNode *tmp=slow->next;
slow->next=slow->next->next;
delete tmp;
return newHead->next;
}
三、链表相交
思路:如果链表相交,A+B的总路程肯定有相等的节点,这个节点的位置就是相交的位置。
ListNode *getIntersectionNode(ListNode *headA, ListNode *headB) {
ListNode*A =headA,*B=headB;
while(A!=B){
A=A!=nullptr?A->next:headB;
B=B!=nullptr?B->next:headA;
}
return A;
}
四、环形链表
思路:数学知识鸽巢原理,如果有换,走两步和走一步一定能相遇。接下来只需要判断一下环的入口位置即可。
- f=2s (快指针每次2步,路程刚好2倍)
- f = s + nb (相遇时,刚好多走了n圈)
推出:s = nb,从head结点走到入环点需要走 : a + nb, 而slow已经走了nb,那么slow再走a步就是入环点了。
ListNode *detectCycle(ListNode *head) {
ListNode*fast=head,*slow=head;
while(true){//得到相遇节点
if(fast==nullptr||fast->next==nullptr)return nullptr;
fast=fast->next->next;
slow=slow->next;
if(fast==slow)break;
}//一起走直到再次相遇就是环的入口
fast=head;
while(fast!=slow){
fast=fast->next;
slow=slow->next;
}
return fast;
}
总结
学会链表的中的一些数学思想有助于我们在理解链表的基础操作上,处理更加复杂的问题!。