/**
* 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) {
ListNode* p=new ListNode(0);
ListNode* p1=NULL;
p->next=head;
head=p;
p1=p;
p=head->next;
while(p!=NULL&&p->next!=NULL){
p1->next=p->next;
p->next=p1->next->next;
p1->next->next=p;
p1=p;
p=p->next;
}
return head->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* removeNthFromEnd(ListNode* head, int n) {
ListNode *p1=new ListNode(0), *p2=head;
p1->next=head;
head=p1;
while(n-->0){
p2=p2->next;
}
while(p2!=NULL){
p2=p2->next;
p1=p1->next;
}
p1->next=p1->next->next;
return head->next;
}
};
用双指针,根据所给的N,一个指针先走N步,笔者的代码中有1步是由虚拟头结点多出来的,之后两之中以相同的步长访问之后的节点,直到先走的指针访问到NULL,也就是尾部,后走的指针开始执行删除后继节点的操作。
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode(int x) : val(x), next(NULL) {}
* };
*/
class Solution {
public:
ListNode *getIntersectionNode(ListNode *headA, ListNode *headB) {
ListNode *p1=headA, *p2=headB, *result=NULL;
int len1,len2;
for(len1=0;p1!=NULL;p1=p1->next,len1++);
for(len2=0;p2!=NULL;p2=p2->next,len2++);
p1=headA;
for(int i=len1-len2;i-->0;p1=p1->next);
p2=headB;
for(int i=len2-len1;i-->0;p2=p2->next);
while(p1!=NULL){
if(p1==p2){
result=p1;
break;
}
p1=p1->next;
p2=p2->next;
}
return result;
}
};
两个头向后计算链表长度时,交点以及交点后的长度相同,所以长度的差异只会由交点前的部分产生,所以通过分别从两个头开始遍历链表获取两个长度,对交点前的长度进行对齐,就能保证两端同步向后访问后继节点的过程中一定能同时到达交点。
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode(int x) : val(x), next(NULL) {}
* };
*/
class Solution {
public:
ListNode *detectCycle(ListNode *head) {
ListNode *sp=head, *fp=head;
if(fp==NULL){
return NULL;
}
do{
if(fp->next==NULL){
return NULL;
}else{
if(fp->next->next==NULL){
return NULL;
}else{
sp=sp->next;
fp=fp->next->next;
}
}
}while(fp!=sp);
for(sp=head;sp!=fp;sp=sp->next,fp=fp->next);
return sp;
}
};
这题通过快慢指针判断是否有环,很好理解,步长为1和2的两指针在有环的情况下必定会再次相遇,这不难理解,不过之后的寻找环的起始的方法甚是巧妙,代码随想录中给的解释是这样的
对于n>1的情况,则直接给了我们结论,即n=1时的代码也可以处理n>1的情况。笔者试着证明了一下。各个变量与随想录中给的一样。易得:
也就是:
将x放在左式,其余全部放到右式得:
从快指针与慢指针第一次相遇的位置以步长为1的速度到达环的起始节点所需的步数为:
也就是:
也是不小于0的整数。
不难发现,时,x也就等于从快指针与慢指针第一次相遇的位置以步长为1的速度到达环的起始节点的长度,所以n>1与n=1两种情况下代码的实现是完全一样的。