算法小白训练营日记,笔记为自用,若有错误感谢指出
--今日任务--:24. 两两交换链表中的节点 ,19.删除链表的倒数第N个节点 ,面试题 02.07. 链表相交 ,142.环形链表II ,总结
24.两两交换链表中的节点
题目链接:24. 两两交换链表中的节点 - 力扣(LeetCode)
采用虚拟头结点的方式,循环结束标志:cur->next==NULL&&cur->next->next==NULL;两者不能交换,若交换,cur->next==NULL时,先判断cur->next->next,操作空指针报错。
定义temp保存cur->next,temp1保存cur->next->next->next,防止链表连接指针变化时找不到下一节点。最后删除虚拟头结点。
具体代码如下:
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* temp=cur->next;
ListNode* temp1=cur->next->next->next;
cur->next=cur->next->next;
cur->next->next=temp;
cur->next->next->next=temp1;
cur=cur->next->next;
}
ListNode* res=dummyhead->next;
delete dummyhead;
return res;
}
};
19.删除链表的倒数第N个节点
题目链接:19. 删除链表的倒数第 N 个结点 - 力扣(LeetCode)
先设置虚拟头结点,保证没有头结点操作不同的情况。查找第n个节点的方法使用双指针,快指针先走n个,使两个指针之间相距为n,快慢指针一起变化,直到快指针走到NULL时,慢指针指向倒数第n个节点。为删除倒数第n个节点,需要找到此节点的前一个节点,则使慢指针指向倒数第n+1个节点,所以快指针先走n+1个。当找到第n+1节点时,使slow->next=slow->next->next;释放所删除节点和虚拟头结点。
具体代码如下:
class Solution {
public:
ListNode* removeNthFromEnd(ListNode* head, int n) {
ListNode* dummyhead=new ListNode(0);
dummyhead->next=head;
ListNode* fast=dummyhead;
ListNode* slow=dummyhead;
while(n--&&fast!=NULL){
fast=fast->next;
}
fast=fast->next;
while(fast!=NULL){
fast=fast->next;
slow=slow->next;
}
ListNode* temp=slow->next;
slow->next=slow->next->next;
delete temp;
ListNode* res=dummyhead->next;
delete dummyhead;
return res;
}
};
面试题 02.07. 链表相交
题目链接:面试题 02.07. 链表相交 - 力扣(LeetCode)
定义指针curA,curB,为查找节点相交,可查找指针所指向的节点是否相同,则需把两链表尾部对齐。求出链表长度,并求出两个链表长度的差值,若A链表比B链表长,则交换两链表的指针和长度,使curA一直指向最长的链表。将两指针重新指向表头,然后根据链表长度差值让curA移动到,和curB对齐的位置,再进行遍历,若curA=curB,则两指针所指向的节点相同,两链表相交。
具体代码如下:
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;
if(lenA<lenB){
swap(lenA,lenB);
swap(curA,curB);
}
int n=lenA-lenB;
while(n--&&curA!=NULL){
curA=curA->next;
}
while(curA){
if(curA==curB){
return curA;
}
curA=curA->next;
curB=curB->next;
}
return NULL;
}
};
142.环形链表II
思路好神奇的题!运用双指针的解法。
定义双指针fast,slow,fast一次走两个节点,slow一次走一个节点,相对于slow,fast每次多走一个节点,所以链表若存在环,两指针必定会相交且fast指针不会跳过slow指针。
若链表存在环时,设链表非环部分为x节点,从环的入口处到两指针相遇节点数为y,环中剩余节点数为z,则当slow指针走x+y节点时,设fast指针在环中已走了n圈,所以此时fast指针走了x+n(y+z)+y个节点,因为fast指针走过节点数为两倍的slow,所以此式可表示为2(x+y)=x+n(y+z)+y,变换后可得x=(n-1)(z+y)+z,z+y为环的长度,走完一圈环又回到入口处,可得x=z,所以从起点到入口处的节点数x等于两指针相交后走到入口处剩余的节点数z相等,即当两指针相遇后定义index1指针从head处遍历,定义另一指针index2从相交处开始遍历,直到两指针相交处即为环形链表入口。
具体代码如下:
class Solution {
public:
ListNode *detectCycle(ListNode *head) {
ListNode* fast=head;
ListNode* slow=head;
while(fast!=NULL&&fast->next!=NULL){
fast=fast->next->next;
slow=slow->next;
if(fast==slow){
ListNode* index1=fast;
ListNode* index2=head;
while(index1!=index2){
index1=index1->next;
index2=index2->next;
}
return index1;
}
}
return NULL;
}
};
总结
链表题中对头结点和其他节点操作不同的情况下添加虚拟头结点解决,掌握链表的定义和增删改查操作的思路以及正确书写算法代码是很重要的,反转链表,删除倒数第n个节点,链表相交,环形链表中又和双指针的方法结合。
明天休息日再巩固一遍这一周所做的题目和拓展题,熟练掌握数组及链表的知识。