代码随想录第4天 | 24. 两两交换链表中的节点、19.删除链表的倒数第N个节点、面试题 02.07. 链表相交、142.环形链表II 链表总结
题目:24.两两交换链表中的节点
思路:
设置虚拟头结点,双指针+临时指针,(感觉也能递归,未尝试)
时间复杂度:O(n)
空间复杂度:O(1)
坑:
1.又忘了 else{}和return
2.试图访问空指针,多个条件的顺序问题及"&&""||"问题,cur->next要写在cur->next->next前面
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode() : val(0), next(nullptr) {}
* ListNode(int x) : val(x), next(nullptr) {}
* ListNode(int x, ListNode *next) : val(x), next(next) {}
* };
*/
class Solution {
public:
ListNode* swapPairs(ListNode* head) {
if (head == nullptr)
return head;
else {
ListNode* dummyhead = new ListNode(0);
dummyhead->next = head;
ListNode* cur = dummyhead;
ListNode* post = head;
ListNode* pre = new ListNode(0);
ListNode* tmp;
while (cur->next!=nullptr&&cur->next->next!=nullptr) { //优化后,报错,
/*1. 是“&&”不是“||”, 或的话,若cur->next为nullptr,则cur->next->next就访问空指针了,
2.cur->next要写在cur->next->next前面,理由同上
*/
pre = post->next;
tmp = pre->next;
cur->next = pre;
pre->next = post;
post->next=tmp; //提交heap-use-after-free报错了,我的链表交换后,这里断了,
cur = post;
post = tmp;
}
return dummyhead->next;
}
}
};
/*未优化版本
while (post!=nullptr) { //可优化,循环结束条件不对,看循环体结束部分来思考
pre = post->next;
if(pre==nullptr){ //缺少判断条件 长度为奇数的链表 这部分可优化
return dummyhead->next;
}
tmp = pre->next;
cur->next = pre;
pre->next = post;
post->next=tmp; //提交heap-use-after-free报错了,我的链表交换后,这里断了,
cur = post;
post = tmp;
}
*/
补充:
1.heap-use-after-free on address
尾节点如果没有rear->next=NULL;这个链表就会错呢? 尾节点没有明确指向,链表不完整,计算机认为链表未结束
2.悬挂指针(Dangling Pointer)。如果我们试图访问已经被释放的内存,就会触发"heap-use-after-free"错误。
题目:19.删除链表的倒数第N个节点
思路:
1.遍历链表获取链表长度,然后删除结点,释放被删除节点
2.进阶要求是,使用一趟扫描实现-->随想录思路 啊 是快慢指针,快指针先走N+1步,
时间复杂度: O(n)
空间复杂度: O(1)
坑:
试图访问空指针,主要在cur->next时,cur可能为空指针
/** Definition for singly-linked list.同上*/
class Solution {
public:
ListNode* removeNthFromEnd(ListNode* head, int n) {
ListNode* dummyHead=new ListNode(0);
dummyHead->next=head;
ListNode* fast=dummyHead; //fast和slow初始指向虚拟head不是head
ListNode* slow=dummyHead;
ListNode* tmp;
n++; //删除结点,slow要指向被删除结点的前一个节点,所以fast要多走一步,slow和fast相差n+1步
while(n--&&fast!=nullptr){ //错误,需要判断fast是否为空,
fast=fast->next;
}
while(fast!=nullptr){ //错误,试图访问空指针 fast不为空 不用->next
fast=fast->next;
slow=slow->next;
}
tmp=slow->next;
slow->next=slow->next->next;
delete tmp;
return dummyHead->next;
}
};
补充:
个人对快慢双指针还是没有理解到位
题目:面试题02.07.链表相交
思路:
1.两个这指针分别指向a,b,两层循环遍历,比较->next是否相等,有点繁琐
2.看了leetcode的引导式提示:从两链表长度相同时相交到不同长度,一个先走差值步,使得二者相同才判断;
时间复杂度:O(n + m)
空间复杂度:O(1)
坑:
- 当两链表长度相同时,两链表不相交可以和相交放一起判断
- 使用pa->next判空,则少算了最后一个pa节点
- 没比较两链表长度,就默认进行下去了;
/** Definition for singly-linked list.同上*/
class Solution {
public:
ListNode* getIntersectionNode(ListNode* headA, ListNode* headB) {
ListNode* pA = headA;
ListNode* pB = headB;
int m = 0, n = 0, diff = 0; // diff表示两链表的差值 (用英语gap也行)
pA = headA; // 指针返回头结点
pB = headB;
while (pA != nullptr) { // 错误,pa->next判空,则少算了最后一个pa节点
pA = pA->next;
m++;
}
while (pB != nullptr) {
pB = pB->next;
n++;
}
pA = headA;
pB = headB;
// 错误,m和n的大小没有判断,
if (m < n) { // 交换使得,pA和m表示较长的链表
swap(pA, pB);
swap(m, n);
}
diff = m - n;
while (diff--) {
pA = pA->next;
}
while (pA!=nullptr) {
if(pA==pB)
return pA;
pA = pA->next;
pB = pB->next;
}
return NULL;
}
};
题目:142.环形链表Ⅱ
思路:
有点印象,快慢双指针,但想不出来
双指针技术本质上是依赖 速度 或 起始位置不同 的两个指针对于链表的遍历来实现对问题的快速解决
很好的追击问题,使我的头大,物理加数学
快指针比慢指针每次多走一步,有环,那他们终会相遇
相遇时,头结点到入环口的距离等于相遇点到入环口的距离
坑:
/** Definition for singly-linked list.同上*/
class Solution {
public:
ListNode *detectCycle(ListNode *head) {
ListNode* fast=head;
ListNode* slow=head;
//fast=fast->next->next; //报错 超出时间限制 这步位置不对
while(fast!=nullptr&&fast->next!=nullptr){ //fast->next也不为空,fast一次走两步
fast=fast->next->next;
slow=slow->next;
if(fast==slow){
fast=head;
while(fast!=slow){
fast=fast->next;
slow=slow->next;
}
return fast;
}
}
return nullptr;
}
};
补充:
想不明白 就画图吧
链表总结
链表类的题主要还是看思路,想得到关键,就后面很顺利
双指针解题:
1.指针相邻:删除某个结点,或交换两个结点
2.指针不相邻,快满指针间隔n步,或者速度相差n倍

浙公网安备 33010602011771号