24. 两两交换链表中的节点
题目链接/文章讲解/视频讲解: https://programmercarl.com/0024.%E4%B8%A4%E4%B8%A4%E4%BA%A4%E6%8D%A2%E9%93%BE%E8%A1%A8%E4%B8%AD%E7%9A%84%E8%8A%82%E7%82%B9.html
- 设置虚拟头节点
- 每次需要交换两个点,所以需要next和next->next 都存在
- cur从dummynode开始
- 设置两个临时指针
- 0->2
- 1->3
- 2->1
- cur后移两位
ListNode* swapPairs(ListNode* head) {
ListNode* dummynode = new ListNode(0);
dummynode->next = head;
ListNode* cur = dummynode;
while(cur->next!=nullptr&&cur->next->next!=nullptr){
ListNode* tmp = cur->next;
ListNode* tmp2 = cur->next->next;
cur->next = tmp2;
tmp->next = tmp2->next;
tmp2->next = tmp;
cur = cur->next->next;
}
return dummynode->next;
}
19.删除链表的倒数第N个节点
https://programmercarl.com/0019.%E5%88%A0%E9%99%A4%E9%93%BE%E8%A1%A8%E7%9A%84%E5%80%92%E6%95%B0%E7%AC%ACN%E4%B8%AA%E8%8A%82%E7%82%B9.html
双指针,fast先走n+1步,slow再走,这样fast遍历完时slow走到倒数n-1个节点,此时将slow的next指针调整到next->next
ListNode* removeNthFromEnd(ListNode* head, int n) {
ListNode* dummynode = new ListNode(0);
dummynode->next = head;
ListNode* fast = dummynode;
ListNode* slow = dummynode;
while(n--&&fast!=nullptr){
fast = fast->next;
}
fast = fast->next;
while(fast!=nullptr){
fast = fast->next;
slow = slow->next;
}
slow->next = slow->next->next;
return dummynode->next;
}
面试题 02.07. 链表相交
题目链接/文章讲解:https://programmercarl.com/%E9%9D%A2%E8%AF%95%E9%A2%9802.07.%E9%93%BE%E8%A1%A8%E7%9B%B8%E4%BA%A4.html
第一次遍历,记录两个表长及表长差,将更长的表指针先移动表长差位,之后一同移动,如果两个相同,则是相交处,如果遍历完没有相同,则不相交
ListNode *getIntersectionNode(ListNode *headA, ListNode *headB) {
ListNode* curA = headA;
ListNode* curB = headB;
int la = 0,lb = 0,distance;
while(curA != nullptr){
curA = curA->next;
la++;
}
while(curB != nullptr){
curB = curB->next;
lb++;
}
curA = headA;
curB = headB;
if(lb>la){
swap(la,lb);
swap(curA,curB);
}
distance = la-lb;
while(distance--){
curA = curA->next;
}
while(curA!=nullptr){
if(curA == curB){
return curA;
}
curA = curA->next;
curB = curB->next;
}
return NULL;
}
142.环形链表II
题目链接/文章讲解/视频讲解:https://programmercarl.com/0142.%E7%8E%AF%E5%BD%A2%E9%93%BE%E8%A1%A8II.html
判断是否有环
可以使用快慢指针法,分别定义 fast 和 slow 指针,从头结点出发,fast指针每次移动两个节点,slow指针每次移动一个节点,如果 fast 和 slow指针在途中相遇 ,说明这个链表有环。
怎样找到环的起始点
设链表共有 a+ba+ba+b 个节点,其中 链表头部到链表入口 有 aaa 个节点(不计链表入口节点), 链表环 有 bbb 个节点(这里需要注意,aaa 和 bbb 是未知数,例如图解上链表 a=4a=4a=4 , b=5b=5b=5);设两指针分别走了 fff,sss 步,则有:
fast 走的步数是 slow 步数的 222 倍,即 f=2sf = 2sf=2s;(解析: fast 每轮走 222 步) fast 比
slow 多走了 nnn 个环的长度,即 f=s+nbf = s + nbf=s+nb;( 解析: 双指针都走过 aaa
步,然后在环内绕圈直到重合,重合时 fast 比 slow 多走 环的长度整数倍 )。 将以上两式相减得到 f=2nbf =
2nbf=2nb,s=nbs = nbs=nb,即 fast 和 slow 指针分别走了 2n2n2n,nnn 个环的周长。接下来该怎么做呢?
如果让指针从链表头部一直向前走并统计步数k,那么所有 走到链表入口节点时的步数 是:k=a+nbk=a+nbk=a+nb ,即先走 aaa
步到入口节点,之后每绕 111 圈环( bbb 步)都会再次到入口节点。而目前 slow 指针走了 nbnbnb 步。因此,我们只要想办法让
slow 再走 aaa 步停下来,就可以到环的入口。但是我们不知道 aaa 的值,该怎么办?依然是使用双指针法。考虑构建一个指针,此指针需要有以下性质:此指针和 slow 一起向前走 a
步后,两者在入口节点重合。那么从哪里走到入口节点需要 aaa 步?答案是链表头节点head作者:Krahets 链接:https://leetcode.cn/problems/linked-list-cycle-ii/
来源:力扣(LeetCode) 著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
ListNode *detectCycle(ListNode *head) {
ListNode *fast = head;
ListNode *slow = head;
while(fast!=nullptr&&slow!=nullptr&&fast->next!=nullptr){
fast = fast->next->next;
slow = slow->next;
if(slow == fast){
fast = head;
while(slow != fast){
fast = fast->next;
slow = slow->next;
}
return fast;
}
}
return nullptr;
}