代码随想录算法训练营第四天|24. 两两交换链表中的节点 , 19.删除链表的倒数第N个节点 , 面试题 02.07. 链表相交 , 142.环形链表II
24. 两两交换链表中的节点
个人感觉这个不太难,刚开始打算用步进值为2,来搞,但是没有想到链表应该是怎么样的,
原来可以直接用:
1 cur = cur->next->next
学到了,这是我自己写的代码:
1 ListNode* MyLinkedList::swapPairs(ListNode* head) 2 { 3 ListNode* dummyHead = new ListNode(); 4 dummyHead->next = head; 5 auto* cur = dummyHead; 6 7 int idx = 0; 8 while (cur->next != nullptr) 9 { 10 if (idx % 2 == 0 && cur->next->next !=nullptr) 11 { 12 auto* first = cur->next; 13 auto* second = cur->next->next; 14 15 first->next = second->next; 16 second->next = first; 17 cur->next = second; 18 } 19 20 idx++; 21 cur = cur->next; 22 } 23 24 return dummyHead->next; 25 }
19.删除链表的倒数第N个节点
笨方法:
1,先得到正序情况下的下标
2,在对这个下标进行删除
需要注意:
1,idx >0
代码:
1 ListNode* MyLinkedList::removeNthFromEnd(ListNode* head, int n) 2 { 3 ListNode* dummyHead = new ListNode(); 4 dummyHead->next = head; 5 ListNode* cur = dummyHead; 6 7 int length = 0; 8 while (cur->next != nullptr) 9 { 10 length++; 11 cur = cur->next; 12 } 13 14 //不算头节点,从0开始 15 cur = dummyHead; 16 int idx = length - n; 17 while (idx > 0) 18 { 19 cur = cur->next; 20 idx--; 21 } 22 23 24 if (cur->next != nullptr) 25 { 26 auto* mid = cur->next; 27 cur->next = mid->next; 28 } 29 30 return dummyHead->next; 31 }
聪明的方法:
1 // 对于倒数来说,主要的步骤是用快慢指针,他们两个的差,就是n 2 // 如果快指针指向的NULL,那么慢指针指向的就是问题节点 3 ListNode* MyLinkedList::removeNthFromEnd(ListNode* head, int n) 4 { 5 ListNode* dummyHead = new ListNode(); 6 dummyHead->next = head; 7 ListNode* fast = dummyHead; 8 ListNode* slow = dummyHead; 9 10 // fast faster n than slow 11 while (n>0) 12 { 13 fast = fast->next; 14 n--; 15 } 16 17 while (slow->next != nullptr) 18 { 19 if (fast->next == nullptr) 20 { 21 auto* target = slow->next; 22 slow->next = target->next; 23 break; 24 } 25 slow = slow->next; 26 fast = fast->next; 27 } 28 29 return dummyHead->next; 30 }
链表相交
暴力解法版:
1 ListNode* MyLinkedList::getIntersectionNode(ListNode* headA, ListNode* headB) 2 { 3 ListNode* dummyHeadA = new ListNode(); 4 dummyHeadA->next = headA; 5 ListNode* dummyHeadB = new ListNode(); 6 dummyHeadB->next = headB; 7 8 ListNode* curA = dummyHeadA; 9 ListNode* curB = dummyHeadB; 10 while (curA->next != nullptr) 11 { 12 //注意每一轮都要把B初始化 13 curB = dummyHeadB; 14 while (curB->next != nullptr) 15 { 16 if (curA->next == curB->next) 17 { 18 return curA->next; 19 } 20 21 curB = curB->next; 22 } 23 curA = curA->next; 24 } 25 26 return nullptr; 27 }
聪明的解法:
背景:
因为在链表的结构中,他们只能最后面是相等的,所以为了减少双循环,我们可以让他们齐头并进,只要从最短的链表长度那里出发,就可以解决问题了
代码:
1 // 因为A B 的链表结构,是他们的尾部都是相同的,所以我们可以直接移动到最短的链表的HEAD中 2 ListNode* MyLinkedList::getIntersectionNode(ListNode* headA, ListNode* headB) 3 { 4 ListNode* dummyHeadA = new ListNode(); 5 dummyHeadA->next = headA; 6 ListNode* dummyHeadB = new ListNode(); 7 dummyHeadB->next = headB; 8 9 ListNode* curA = dummyHeadA; 10 ListNode* curB = dummyHeadB; 11 12 int lengthA = 0; 13 int lengthB = 0; 14 //如何快速得到一个链表的长度? -》 只能循环遍历 15 while (curA->next != nullptr) 16 { 17 lengthA++; 18 curA = curA->next; 19 } 20 while (curB->next != nullptr) 21 { 22 lengthB++; 23 curB = curB->next; 24 } 25 //强制 A 最长, B最短 26 if (lengthA < lengthB) 27 { 28 swap(lengthA, lengthB); 29 swap(dummyHeadA, dummyHeadB); 30 } 31 32 curA = dummyHeadA; 33 curB = dummyHeadB; 34 35 int subLength = lengthA - lengthB; 36 while (subLength--) 37 { 38 curA = curA->next; 39 } 40 41 while (curA->next != nullptr) 42 { 43 // 因为是一样的长度,所以不用使用For循环 44 if (curB->next == curA->next) 45 return curA->next; 46 curB = curB->next; 47 curA = curA->next; 48 } 49 50 return nullptr; 51 }
142.环形链表II
1,使用数学的方法
1,原理
快慢节点,两个节点相遇的地方A,从开始的B 到 入口点C 的距离 == A -> C
2,需要注意的地方
即使设置了虚拟头,但是要注意,仍然是要从A开始移动,而不是A的前一位,因为 只要设置了虚拟头,那么B 就是虚拟头
3,代码
1 ListNode* MyLinkedList::detectCycle(ListNode* head) 2 { 3 ListNode* dummyHead = new ListNode(); 4 dummyHead->next = head; 5 6 auto* fast = dummyHead; 7 auto* slow = dummyHead; 8 9 // fast = slow +1, 找到这两个指针相遇的节点 10 auto* meetNode = new ListNode(); 11 while (fast->next != nullptr && fast->next->next!=nullptr) 12 { 13 //因为 fast slow都是从空头节点出发,所以meetNode 也要从空的头节点出发, 14 if (fast->next->next == slow->next) 15 { 16 //不需要预留一位 17 meetNode = slow->next; 18 auto index1 = dummyHead; 19 auto index2 = meetNode; 20 21 // 因为存在没有环的情况,所以在这里进行判断 22 while (index1->next != nullptr) 23 { 24 if (index1->next == index2->next) 25 { 26 return index1->next; 27 } 28 29 index1 = index1->next; 30 index2 = index2->next; 31 } 32 } 33 34 slow = slow->next; 35 fast = fast->next->next; 36 } 37 38 return NULL; 39 }
2,使用set