代码随想录算法训练营第四天| 24. 两两交换链表中的节点、19.删除链表的倒数第N个节点 、面试题 02.07. 链表相交、142.环形链表II
第三四题题解请参考《代码随想录》:https://programmercarl.com/0203.%E7%A7%BB%E9%99%A4%E9%93%BE%E8%A1%A8%E5%85%83%E7%B4%A0.html#%E7%AE%97%E6%B3%95%E5%85%AC%E5%BC%80%E8%AF%BE
我的代码一些代码参考acwing的yxc的
24. 两两交换链表中的节点
先看代码:
class Solution {
public:
ListNode* swapPairs(ListNode* head) {
if(head == NULL || head->next == NULL) return head;
ListNode* dummy = new ListNode();
dummy->next = head;
for(auto p = dummy;p->next && p->next->next;)
{
auto a = p->next,b = p->next->next;
a->next = b->next;
b->next = a;
p->next = b;
p = a;
}
return dummy->next;
}
};
欢迎朋友来看我这个一看就会,一写就费的同学的博客。
读完题目,首先思考一下,这个题目要不要使用没有存储值的头节点,目的是简化代码,不用单独处理头节点head,这里你一看返回的是一个链表,那么大概率是需要一个空节点作为头节点的。然后是交换,交换的话有两种方式可以选择,我画一下图,我用的方式一。
方式一:
方式二:
19.删除链表的倒数第N个节点
先看代码:
我的:
class Solution {
public:
ListNode* removeNthFromEnd(ListNode* head, int n) {
ListNode* dummy = new ListNode();
dummy->next = head;
ListNode* q = head;
int len = 0;
for(auto p = head;p;p = p->next) len++;
if(n == len) dummy->next = head->next;
for(int i = 0;i < len - n - 1;i++) q = q->next;
if(q->next) q->next = q->next->next;
return dummy->next;
}
};
y总的:
class Solution {
public:
ListNode* removeNthFromEnd(ListNode* head, int n) {
auto dummy = new ListNode(-1);
dummy->next = head;
int len = 0;
for (auto p = dummy; p; p = p->next) len ++ ;
auto p = dummy;
for (int i = 0; i < len - n - 1; i ++ ) p = p->next;
p->next = p->next->next;
return dummy->next;
}
};
这个删除倒数的这个也是没有太难,倒数第n个也就是正数第len - n + 1个,然后找到后删除即可,找的时候还是要注意,因为这是链表,所以找的时候要找到被删除节点的前一个节点,然后将指针停在那个位置,再删除。这里一对比可以看出大佬的代码不愧是大佬的代码,首先简洁,而且显示出缜密的思考,我的还要去判断删除倒数的最后一个节点,也就是第一个节点还要单独拿出来,因为我的指针是从head开始的,不是从dummy开始的。
面试题 02.07. 链表相交
看代码:
class Solution {
public:
ListNode *getIntersectionNode(ListNode *headA, ListNode *headB) {
ListNode* p = headA;
ListNode* q = headB;
int lenA = 0,lenB = 0;
for(ListNode* i = headA;i;i = i->next) lenA++;
for(ListNode* j = headB;j;j = j->next) lenB++;
int res = 0;
if(lenA > lenB)
{
res = lenA - lenB;
for(int i = 0;i < res;i++) p = p->next;
}
else
{
res = lenB - lenA;
for(int j = 0;j < res;j++) q = q->next;
}
while(p)
{
if(p == q) return p;
else {
p = p->next;
q = q->next;
}
}
return nullptr;
}
};
这道题看《代码随想录》的思路就行,很简洁易懂。
142.环形链表II
先看代码:
class Solution {
public:
ListNode *detectCycle(ListNode *head) {
if(!head || !head->next) return nullptr;
ListNode* s = head;
ListNode* f = head->next;
while(f)
{
s = s->next,f = f->next;
if(!f) return nullptr; //f因为是走两部,所以每走一步看看f是否到头了
f = f->next; //f走两步
if(s == f) //如果f和s相遇
{
s = head; //s回到起始位置
f = f->next; //f也回到起始位置,注意这里的起始位置是f自己的起始位置,以为他起始的时候就比s多一步
while(s != f) {
s = s->next;
f = f->next;
}
return s;
}
}
return nullptr;
}
};
这里的讲解也看《代码随想录就行》,思路好,画的图也很清晰。
这道题目我还犯了一个二百五的错误,就是找到链表尾,用链表尾的next指向谁,谁就是入口,我真是大聪明,都带环了,那还能找到链表尾,哈哈哈。
总结
做了两天的链表,也是2023年的最后一天做的了,明天就2024年了,这里祝大家元旦快乐。然后也写一下我近连天做链表的一些总结或者套路:
- 读完题目之后,想一下需不需要加空的头节点,来简化代码,不用把头节点head单独拿出来了。
- 链表的头尾会有的时候需要特别考虑。
- 就是能使用for()循环对链表进行移动,有的时候比while好多了,尤其涉及用下标来决定添加或者删除节点的时候。
- 还有一个使当if后有return的时候,看if里面的条件使不成立简洁还是成立简洁。
- 链表题目容易出现越界情况
- 多在纸上画画。