代码随想录算法训练营第四天|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

posted @ 2023-06-10 14:42  博二爷  阅读(920)  评论(0编辑  收藏  举报