代码随想录 第二章 链表part02 24. 两两交换链表中的节点 19.删除链表的倒数第N个节点 面试题 02.07. 链表相交 142.环形链表II

24. 两两交换链表中的节点

/**
 * 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;
    }
};

简单的,交换后原本靠前的节点变为靠后,所以往后移动一步就可以开始下一次交换。

19.删除链表的倒数第N个节点

/**
 * 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,也就是尾部,后走的指针开始执行删除后继节点的操作。

面试题 02.07. 链表相交

/**
 * 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;
    }
};

两个头向后计算链表长度时,交点以及交点后的长度相同,所以长度的差异只会由交点前的部分产生,所以通过分别从两个头开始遍历链表获取两个长度,对交点前的长度进行对齐,就能保证两端同步向后访问后继节点的过程中一定能同时到达交点。

142.环形链表II

/**
 * 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的情况。笔者试着证明了一下。各个变量与随想录中给的一样。易得:

2x+2y=x+y+n(y+z)

也就是:

x+y=n(y+z)

将x放在左式,其余全部放到右式得:

x=(n-1)y+nz

从快指针与慢指针第一次相遇的位置以步长为1的速度到达环的起始节点所需的步数为:

z+n_1(y+z)

也就是:

n_1y+(n_1+1)z

n_1也是不小于0的整数。

不难发现,n_1=n-1时,x也就等于从快指针与慢指针第一次相遇的位置以步长为1的速度到达环的起始节点的长度,所以n>1与n=1两种情况下代码的实现是完全一样的。

代码随想录 第二章 链表part02

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值