题目链接 24. 两两交换链表中的节点 & 19.删除链表的倒数第N个节点 & 面试题 02.07. 链表相交 & 142.环形链表II
今日学习的文章链接和视频链接 24. 两两交换链表中的节点 & 19.删除链表的倒数第N个节点 & 面试题 02.07. 链表相交 & 142.环形链表II
目录
24. 两两交换链表中的节点
自己看到题目的第一想法
看完代码随想录之后的想法
取要翻转的2个节点的前1个节点为cur
,这样可以操作后两个节点和确定循环终止条件。
当链表为空时,和偶数节点的链表一样被处理,因为虚拟节点很好地统一了这种特殊情况。
在交换元素的时候,按顺序进行操作较好。
// 时复 O(n),空复 O(1)
class Solution {
public:
ListNode* swapPairs(ListNode* head) {
ListNode* dummy_head = new ListNode(0, head);
ListNode* cur = dummy_head, * tmp_front = nullptr, * tmp_back = nullptr;
while (cur->next != nullptr && cur->next->next != nullptr) {
tmp_front = cur->next;
tmp_back = cur->next->next->next;
cur->next = cur->next->next;
cur->next->next = tmp_front;
tmp_front->next = tmp_back;
cur = tmp_front; // cur = cur->next->next;
}
return dummy_head->next;
}
};
自己实现过程中遇到哪些困难
看完视频后实现,没有困难
今日收获,记录一下自己的学习时长
自己动手画画,逻辑清楚后写代码真的很爽
19. 删除链表的倒数第 N 个结点
自己看到题目的第一想法
我的第一想法,两遍循环:
// 时复 O(n),空复 O(1)
class Solution {
public:
ListNode* removeNthFromEnd(ListNode* head, int n) {
int sz = 0;
ListNode* dummy_head = new ListNode(0, head);
ListNode* i = head, * pre = nullptr, * tmp = nullptr;
while(i != nullptr) sz++, i = i->next;
i = head, pre = dummy_head;
while (sz-- > n) {
pre = i;
i = i->next;
}
pre->next = i->next;
tmp = i;
delete tmp;
return dummy_head->next;
}
};
看完代码随想录之后的想法
快慢双指针,一遍循环:
// 时/空复 O(n)/O(1)
class Solution {
public:
ListNode* removeNthFromEnd(ListNode* head, int n) {
ListNode* dummy_head = new ListNode(0, head);
ListNode* i = head, * pre = dummy_head, * fast = dummy_head, * slow = dummy_head;
while(n--) {
fast = fast->next;
}
while(fast != nullptr) {
fast = fast->next;
pre = slow;
slow = slow->next;
}
pre->next = slow->next;
delete slow;
return dummy_head->next;
}
};
自己实现过程中遇到哪些困难
注意循环结束条件,同时模拟一遍操作,因为此时不熟悉。
今日收获,记录一下自己的学习时长
- 链表的遍历和删除
- 双指针的使用
面试题 02.07. 链表相交
自己看到题目的第一想法
题干很迷,输入到底是啥?
第一想法+提示:比较的是指针相等而不是数值,时空复杂度O(n)O(1)
class Solution {
public:
ListNode *getIntersectionNode(ListNode *headA, ListNode *headB) {
for(ListNode* i = headA; i != NULL; i = i->next)
for (ListNode* j = headB; j != NULL; j = j->next)
if (i == j) return i;
return NULL;
}
};
看完代码随想录之后的想法
4步:
- 求出2个链表的长度
- 求出2个链表长度差值,确定最长者,后续操作需要移动其指针
- 2个链表形式上尾端对齐(根据题干要求),同时将指针对齐
- 2个链表的指针同时移动,同时比较是否相等
随想录版本:
// 时空复杂度O(n)O(1)
class Solution {
public:
ListNode *getIntersectionNode(ListNode *headA, ListNode *headB) {
int headA_length = 0, headB_length = 0, diff = 0;
ListNode* curA = headA, * curB = headB;
for (ListNode* i = headA; i != NULL; i = i->next) headA_length++;
for (ListNode* i = headB; i != NULL; i = i->next) headB_length++;
if (headA_length < headB_length) {
swap(headA_length, headB_length);
swap(headA, headB);
swap(curA, curB);
}
diff = headA_length - headB_length;
while (diff--) curA = curA->next;
while (curA != NULL && curB != NULL) {
if (curA == curB) return curA;
curA = curA->next;
curB = curB->next;
}
return NULL;
}
};
自己实现过程中遇到哪些困难
题干难以理解,原来就是如图所示,将链表后端对齐
今日收获,记录一下自己的学习时长
链表操作和题干理解
142.环形链表II
自己看到题目的第一想法
两层for循环但是内存会超时。
看完代码随想录之后的想法
单指针是不可以的,因为总会陷入死循环。快慢双指针可以,在直线上快慢双指针不会相遇;
但是在环中,设置fast
步长为2,slow
步长为1,会相遇的。不要和跑步套圈看作同一种,因为此处为离散的,跑步是连续的。fast
相对slow
的速度为1,所以fast
不会跳过slow
。实际上slow
在进入环的第一圈就被追上了,因为fast
速度是其2倍同时不会跳过slow
。
学自随想录:
// 时空复杂度O(n)O(1)
class Solution {
public:
ListNode *detectCycle(ListNode *head) {
ListNode *fast = head, *slow = head;
while(fast != NULL && fast->next != NULL) {
fast = fast->next->next;
slow = slow->next;
if(fast == slow) {
ListNode *index1 = fast, *index2 = head;
while (index1 != index2) {
index1 = index1->next;
index2 = index2->next;
}
return index1;
}
}
return NULL;
}
};
自己实现过程中遇到哪些困难
整个逻辑都是比较复杂的,不仅需要模拟也需要自己列公式。
今日收获,记录一下自己的学习时长
环形链表