您现在的位置是:首页 >其他 >代码随想录算法训练营第四天|24.两两交换链表中的结点 19.删除链表倒数第n个结点 02.07.链表相交 142.环形链表II网站首页其他
代码随想录算法训练营第四天|24.两两交换链表中的结点 19.删除链表倒数第n个结点 02.07.链表相交 142.环形链表II
简介代码随想录算法训练营第四天|24.两两交换链表中的结点 19.删除链表倒数第n个结点 02.07.链表相交 142.环形链表II
目录
LeeCode 24.两两交换链表中的结点
思路:
题目要求不能改变结点内部值,故通过改变指针来完成交换操作。如下图所示——
class Solution {
public:
ListNode* swapPairs(ListNode* head) {
ListNode* dummyHead = new ListNode(0);
dummyHead->next = head;
ListNode* cur = dummyHead;
while(cur->next != NULL && cur->next->next != NULL){
ListNode* tmp = cur->next;
ListNode* tmp1 = cur->next->next->next;
cur->next = cur->next->next;
cur->next->next = tmp;
cur->next->next->next = tmp1;
cur = cur->next->next;
}
return dummyHead->next;
}
};
时间复杂度:O(n) 空间复杂度:O(1)
LeeCode 19.删除链表倒数第n个结点
思路:设置虚拟头结点,左右指针指向头结点,先将右指针右移n个单位,再将左右指针同时右移直至右指针指向链尾,此时左指针指向倒数第n-1的位置,执行删除倒数第n个结点的操作。
class Solution {
public:
ListNode *removeNthFromEnd(ListNode *head, int n) {
ListNode *dummy = new ListNode(0, head);
ListNode *left = dummy, *right = dummy;
while (n--)
right = right->next;
//此时right和left相距n个单位长度
while (right->next) {
left = left->next;
right = right->next;
} //因为两个指针同时同向移动,故距离保持n不变
//当right移动到链表尾端时,left移动到 倒数第n-1 位置处
LinkNode* tmp = left->next;
left->next = left->next->next;
delete tmp;
return dummy->next;
}
};
时间复杂度:O(n) 空间复杂度:O(1)
LeeCode 02.07.链表相交
思路:两个链表若相交,说明有一结点同时存在于两个链表上,如图——
链表AD和链表BD在C点相交,若想找出来相交的点,需先走完AB'段,然后在B'D和BD段寻找是否有相同的结点。
class Solution {
public:
ListNode *getIntersectionNode(ListNode *headA, ListNode *headB) {
ListNode* curA = headA;
ListNode* curB = headB;
int lenA = 0,lenB = 0;
//求两个链表的长度
while(curA != NULL){
lenA++;
curA = curA->next;
}
while(curB != NULL){
lenB++;
curB = curB->next;
}
curA = headA; curB = headB;
//保证A是较长的链表
if(lenB > lenA){
swap(lenA,lenB);
swap(curA,curB);
}
//将curA移动到和curB末尾对齐的位置
int gap = lenA - lenB;
while(gap--){
curA = curA->next;
}
//比较curA和curB是否相同,不同则向后移动
while(curA != NULL){
if(curA == curB){
return curA;
}
curA = curA->next;
curB = curB->next;
}
return NULL;
}
};
时间复杂度:O(m+n) 空间复杂度:O(1)
LeeCode 142.环形链表II
思路:
定义快慢指针,快指针一次走两个结点,慢指针一次走一个结点,若快慢指针相遇,证明链表中存在环。此时定义两个指针,分别指向表头结点和快慢指针相遇的结点,遍历链表直至两指针相遇,相遇处即为环形入口的结点。
class Solution {
public:
ListNode *detectCycle(ListNode *head) {
ListNode* fast = head;
ListNode* slow = head;
while(fast != NULL && fast->next != NULL){
slow = slow->next;
fast = fast->next->next;
//快慢指针相遇的结点即为环形入口的结点
if(fast == slow){
ListNode* index1 = fast;
ListNode* index2 = head;
while(index1 != index2){
index1 = index1->next;
index2 = index2->next;
}
return index2;
}
}
return NULL;
}
};
时间复杂度:O(n) 空间复杂度:O(1)
总结
1.虚拟头结点的使用可以避免单独对涉及头结点的特殊情况进行讨论。
2.说实话,两两交换结点的题目,一堆指针互相交换,是真的很容易迷。虽然理解了每一步要干嘛,但不太懂为什么代码写成这样。o(╥﹏╥)o
3.后两道题一开始都没思路,但看完讲解之后理解了,能把代码顺下来。没写出来主要还是因为只停留在想的层面,没有动手画图解答。链表的题目画图对理解很重要!
风语者!平时喜欢研究各种技术,目前在从事后端开发工作,热爱生活、热爱工作。