24. 两两交换链表中的节点
题目链接/文章讲解/视频讲解: 代码随想录
解题思路
本题考查的是链表的基础操作,但在操作过程中我们画图分析时会发现有时会丢失节点的引用,因此要记录可能会丢失的节点,另外比较重要的就是循环条件要如何写,分为偶数和奇数节点的情况,但我们应要先判断cur->next,否则会发生空指针引用的错误
class Solution {
public:
ListNode* swapPairs(ListNode* head) {
ListNode* dummyHead = new ListNode(0,head);
ListNode* cur = dummyHead; //虚拟头节点
while(cur->next!=nullptr && cur->next->next !=nullptr)
{
ListNode* temp = cur->next;
ListNode* temp1 = cur->next->next->next; //两个临时变量,用于记录节点
cur->next = cur->next->next;
cur->next->next = temp;
temp->next = temp1;
cur = cur->next->next; //节点交换的过程
}
head = dummyHead->next;
delete dummyHead;
return head;
}
};
这里使用两张卡哥的图来表示一下过程
19.删除链表的倒数第N个节点
题目链接/文章讲解/视频讲解:代码随想录
解题思路
利用双指针的思路,让快指针先走n步,然后快慢指针同时移动,这样就可以找到倒数第N个节点(快指针指向空,慢指针指向倒数第N个),但由于我们需要删掉这个节点,因此要找到这个节点的前一个节点,只需要让快指针走N+1步即可
class Solution {
public:
ListNode* removeNthFromEnd(ListNode* head, int n) {
ListNode* dummyHead = new ListNode(0,head);
ListNode* fast = dummyHead;
ListNode* slow = dummyHead;
n++; //让快指针多移动一次,因为我们要操作删除节点的上一个节点
while(n--&&fast!=nullptr)
{
fast = fast->next;
} //快指针先移动,帮助慢指针寻找到删除节点的上一个节点
while(fast!=nullptr)
{
fast = fast->next;
slow = slow->next; //同时移动
}
ListNode* temp = slow->next;
slow->next = temp ->next;
delete temp;
head = dummyHead->next;
delete dummyHead;
return head; //删除操作
}
};
记得清除内存即可
142.环形链表II
题目链接/文章讲解/视频讲解:代码随想录
解题思路
判断是否有环?
利用快慢指针的思想,让快指针一次走两步,慢指针一次走一步,那这样如果有环的话,那么他们必定在环内相遇,如果没有环,那么不会相遇
快指针是以一步一步去逼近慢指针的,因此必定会相遇
如果有环,那么如何知道环的入口处呢?
利用卡哥的思路
动画演示
class Solution {
public:
ListNode *detectCycle(ListNode *head) {
ListNode* fast =head;
ListNode* slow = head; //定义快慢指针
while(fast!=nullptr && fast->next!=nullptr) //避免对空指针的操作
{
fast = fast->next->next;
slow=slow->next; //快指针一次走两个,慢指针一次走一个
if(fast == slow) //当相遇时代表有环
{
ListNode* index1 = head;
ListNode* index2 = fast; //在相遇节点分别定义两个指针求出入口
while(index1!=index2)
{
index1=index1->next;
index2 = index2->next; //让他们分别往后移动即可找到入口
}
return index1;
}
}
return nullptr; //没找到入口则返回空
}
};
- 时间复杂度: O(n),快慢指针相遇前,指针走的次数小于链表长度,快慢指针相遇后,两个index指针走的次数也小于链表长度,总体为走的次数小于 2n
- 空间复杂度: O(1)
面试题 02.07. 链表相交
题目链接/文章讲解:代码随想录
解题思路
关键在于如何让两个链表同时开始比较,求出两个链表长度,并将长的链表指针移动他们之间的距离即可,利用代码随想录的图理解一下,注意不能对空指针的判断,同时注意值相同,并不代表节点相交,只有地址相同,才是相交节点
class Solution {
public:
ListNode *getIntersectionNode(ListNode *headA, ListNode *headB) {
ListNode* curA = headA;
ListNode* curB = headB;
int lenA=0,lenB=0;
while(curA!=NULL)
{
curA=curA->next;
lenA++;
}
while(curB!=NULL)
{
curB = curB->next;
lenB++;
} //求两个链表长度
curA = headA;
curB = headB; //两个指针回到头节点
if(lenA<lenB)
{
swap(lenA,lenB);
swap(curA,curB); //以A为长链表
}
int gap = lenA-lenB;
while(gap--&&curA!=NULL)
{
curA = curA->next; //移动curA指针和curB指针对齐
}
while(curA!=NULL && curB!=NULL)
{
if(curA==curB)
return curA; //开始比较,如果地址相同则返回相交节点
else
{
curA=curA->next;
curB=curB->next; //否则判断下一个
}
}
return NULL; //如果没有则返回NULL
}
};
- 时间复杂度:O(n + m)
- 空间复杂度:O(1)
收获
今天的收获最大的主要是环形链表,让我茅厕顿开,同时链表相交和删除倒数N节点,都是让一个指针先移动,链表相交则是对齐后进行比较,同时比较重要的一个就是对于空指针引用的判断,其次是可以利用index进行while的判断,在面试题中是自己计算出来进行对齐的,马上进入哈希表环节啦,是我不熟悉的领域,继续加油