代码随想录训练营第四日|24. 两两交换链表中的节点 、19.删除链表的倒数第N个节点 、面试题 02.07. 链表相交

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

题目链接/文章讲解/视频讲解: 代码随想录

1.这种while的判断语句就看最后一次进入循环的是什么,这里最后进入循环的是偶数:最后两个节点(->next节点存在,->next->next节点存在),奇数不进入循环了(->next->next为空),剩一个节点不访问了。

 while(cur->next != nullptr && cur->next->next != nullptr)

2.弄清楚指针的指向,画个图不容易错,比如cur->next变化了,之后的使用别忘了

 cur->next=cur->next->next;
 cur->next->next=temp;

代码

class Solution {
public:
    ListNode* swapPairs(ListNode* head) {
        ListNode *prehead=new ListNode(0);
        prehead->next=head;
        ListNode *cur=prehead;
        ListNode *temp;
        ListNode *tep;
        while(cur->next != nullptr && cur->next->next != nullptr)
        //奇数则->next->next为空,只剩一个节点了不再交换 比如只有一个头节点
        //满足这两个条件,说明至少有两个节点可以交换
        {
            tep=cur->next->next->next;
            temp=cur->next;
            cur->next=cur->next->next;
            cur->next->next=temp;
            temp->next=tep;
            cur=temp;
        }
        head=prehead->next;
        delete prehead;
        return head;
    }
};

二、删除链表的倒数第N个节点

题目链接/文章讲解/视频讲解: 代码随想录

1.悬挂指针报错问题

本题应该是要返回head=prehead->next;当时没有发现这个问题,一直出现heap-use-after-free on address报错,报错原因是你把prehead的内存释放了,但是head指针仍然指向该地址,导致的报错

        head=prehead;
        delete prehead;
        return head;

2.本题的暴力解法是(虚拟头节点) cur指针指向虚拟头节点,求出数组长度,减去n,然后循环差值次,让指针到达要删除节点的前一个节点,然后进行删除的操作

3.本题可以用双指针进行优化,将求长度和减去n,循环操作合并操作

可以发现fast指针到达末端的时候,和slow到达要删除节点的前一个节点相差n次->next

采用双指针不同出发位置,(相差n次->next)来实现减去n这个操作,即可以让fast指针到达末端时(即求出数组长度),slow指针到达删除节点的前一个节点

代码

class Solution {
public:
    ListNode* removeNthFromEnd(ListNode* head, int n) {
        ListNode *prehead=new ListNode(0);
        prehead->next=head;
        ListNode *slow=prehead;
        ListNode *fast=prehead;
        while(n--)
        {
            fast=fast->next;
        }
        while(fast->next)
        {
            fast=fast->next;
            slow=slow->next;
        }
        ListNode *del=slow->next;
        slow->next=slow->next->next;
        delete del;
        head=prehead->next;
        delete prehead;
        return head;
    }
};

三、链表相交

题目链接/文章讲解: 代码随想录

1.相交的意思是:相交的节点地址相同,其中val和next指针的相同,所以一旦相同后面都相同

2.因为相交后面是相同的,所以先对齐长度(定义首个指针指向的位置直到空地址的节点个数)(以最短的标准)

3.采用求取长度做差,相差几个,指向长的链表的头节点的指针向后移动几位

4.小技巧:运用swap,保持B链表长度大于A,sizeA<sizeB,(swap(sizeA,sizeB))交换指向链表的指针,(swap(curA,curB))或者交换两个链表的地址(swap(headA,headB))

不然会复杂一点,进行两种情况的讨论,这样即保持一种情况,A短B长

 if(sizeA>sizeB)
    {
        swap(sizeA,sizeB);
        swap(headA,headB);
    }
    curA=headA;
    curB=headB;
curA=headA;
curB=headB;
if(sizeA>sizeB)
{
   swap(sizeA,sizeB);
   swap(curA,curB);
}

代码: 

class Solution {
public:
    ListNode *getIntersectionNode(ListNode *headA, ListNode *headB) 
{
    ListNode *curA=headA;
    ListNode *curB=headB;
    int sizeA=0,sizeB=0;
    //求取长度
    while(curA)
    {
        curA=curA->next;
        sizeA++;
    }
    while(curB)
    {
        curB=curB->next;
        sizeB++;
    }
    //计算差值
    if(sizeA>sizeB)
    {
        swap(sizeA,sizeB);
        swap(headA,headB);
    }
    curA=headA;
    curB=headB;
    int c=sizeB-sizeA;
    //移动指针
    while(c--)
    {
        curB=curB->next;
    }
    //判断是否有交点
    while(curB)
    {
        if(curA==curB)
        {
            return curB;
        }
        else
        {
            curA=curA->next;
            curB=curB->next;
        }
    }
    return NULL;
}
};

四、环形链表II

题目链接/文章讲解/视频讲解:代码随想录

1.这题比较复杂的是逻辑的思考

2.采用快慢指针 ,一个快一个慢,如果有环则一定会相遇。

3.两个重要信息:快指针走的路程是慢指针的两倍

                             快慢指针相遇,即已知相遇的位置

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

当n=1时 x=z;即一个指针从头节点出发(x为它走的路程),会和从相遇的位置出发的指针(z为它走的路程)在环的入口处相遇

当n!=1时,x = n (y + z) - y,按照n=1的逻辑,转化为 x = (n - 1) (y + z) + z(因为已知相遇位置了,所以z是有用的,不知道环的入口,y是用不来的)

n>1说明x比较长,z+y比较短,一个指针从头节点出发(x为它走的路程),一个指针从相遇的位置出发((n - 1) (y + z) + z为它走的路程,先走n-1圈,再走z),最后再环的入口处相遇

代码

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 (slow == fast) {
                ListNode* index1 = fast;
                ListNode* index2 = head;
                while (index1 != index2) {
                    index1 = index1->next;
                    index2 = index2->next;
                }
                return index2; // 返回环的入口
            }
        }
        return NULL;
    }
};

五、链表总结

1.一般涉及到 增删改操作,用虚拟头结点都会方便很多, 如果只能查的话,用不用虚拟头结点都差不多。
2.注意操作空指针的问题,边界问题
3.一般在循环中要出现的节点,是否为空在while()语句中判断了
4.双指针的使用:①删除倒数第n个节点,使用双指针,一前一后
                            ②环形链表 快慢指针
  • 19
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值