代码随想录算法训练营第四天|24. 两两交换链表中的节点 ● 19.删除链表的倒数第N个节点 ● 面试题 02.07. 链表相交 ● 142.环形链表II

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


随想录文字讲解:代码随想录 (programmercarl.com)

随想录视频讲解:帮你把链表细节学清楚! | LeetCode:24. 两两交换链表中的节点_哔哩哔哩_bilibili

状态:做出来了


最开始看到这道题目以为是像冒泡排序一样依次交换,写完发现不通过,才发现是交换完一对后去交换下一对。但是交换的写法是不变的,唯一的变化是循环时的条件。

由于是从头部开始就有可能交换,所以使用链表常用的虚拟头节点法,使头节点也具有一般性,最后返回fakehead->next就ok了。

循环条件:由虚拟头节点开始判断,即第一个交换对的前面一个节点,循环后指针跳到交换对的最后一个节点,即下一个交换对的前面一个节点。每次循环会出现三种可能,即指针后有两个数(可循环),一个数(不可循环),没有数(不可循环)

所以循环条件为:

 while(p->next!=NULL&&p->next->next!=NULL)

然后为交换:

一次交换对的交换其实涉及四个点的问题。

两个点的交换涉及第一个点前驱的变化和第二个点后继的变化,所以变化的次序很关键,应用temp进行存储。代码如下:

            ListNode*  temp=p->next;
            p->next=temp->next;
            temp->next=p->next->next;
            p->next->next=temp;

应当注意的是在把图中的0的后继改为2后,在让2的后继为1前,应先让1的后继变为2的后继(即3),否则会把3丢失掉。因为1被temp存储了,所以可以最后更新2的后继为temp。

循环后别忘了更新节点。


 随想录做法:

和我的做法思路大致一样,但是运用了两个temp来存储值,使节点的更新更简单明了。

            ListNode* tmp = cur->next; // 记录临时节点
            ListNode* tmp1 = cur->next->next->next; // 记录临时节点

            cur->next = cur->next->next;    // 步骤一
            cur->next->next = tmp;          // 步骤二
            cur->next->next->next = tmp1;   // 步骤三


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


随想录文字讲解:代码随想录 (programmercarl.com)

随想录视频讲解:链表遍历学清楚! | LeetCode:19.删除链表倒数第N个节点_哔哩哔哩_bilibili

状态:做出来了


第一眼暴力做法是一次遍历求总节点数,第二次去删节点。但是突然想起曾经做过这道题,可以用双指针法用一次遍历来找到应该删除的节点。

找到倒数第N个节点,可以使用两个指针,让一个指针先走a次,使得当一个指针遍历完整个数组时另一个指针刚好落在应被删除的指针上。由于这道题给出的是单链表,所以应落在应被删除的节点的前一个节点。

要删除倒数第N个节点,就让p先走N步,这样N走到空指针时,q指针所在节点就是正好应被删除的节点。

根据这个原理,我们可以分为两种情况来判断。

第一种:p走N步后不需后续循环直接走到空指针上,即删除头节点,直接删除后返回即可。

第二种:在判断不是删除头节点后,让p走到最后一个节点(而不是空指针),这样q所在的位置就是应被删除节点的前驱(因为整体前移了一个),这时直接删除就行了。

代码如下:

class Solution {
public:
    ListNode* removeNthFromEnd(ListNode* head, int n) {
        ListNode* p=head;
        ListNode* q=head;
        for(int i=0;i<n;i++)
        q=q->next;
        if(q==NULL)
        {
            head=head->next;
            return head;
        }
        while(q->next!=NULL)
        {
            q=q->next;
            p=p->next;
        }
        p->next=p->next->next;
        return head;
    }
};

随想录做法:

随想录的做法也是双指针算法,但是用虚拟头节点来使头节点的删除具有一般性,再对需要走的步数进行调整 ,使快指针遍历结束时找出被删除节点。



面试题 02.07. 链表相交  

随想录文字讲解:代码随想录 (programmercarl.com)

状态:没做出来


从胸有成竹到傻眼。

读完题目这道题的做法我就已经有了一个大概,先让两个链表全遍历到尾节点,判断指针是否相等,如果相等就证明有交点,反之则无交点。有交点的话,我让两个链表的尾节点分别与他们的头节点相连,然后两个分别指向两个链表的指针按不同的移动距离循环,最终会找到地址相同的点,即交点,再把链表复原即可

由于想法过于顺利和想当然,我在报错后很长时间都没找到错在哪,错误如下:

第一,也是最根本的错误:当两个链表的尾节点地址相同的时候,他们也就是一个尾节点,让两个链表的尾节点分别与他们的头节点相连是不现实的,因为这会让同一个尾节点赋值两次。

第二,假设能形成两个循环链表,那在步调不同的循环中找到的第一个地址相同的点未必是交点,也有可能是交点之后的某一个点。

写法宣告失败,


随想录做法:

真是简单明了,甘拜下风。

我在写这道题的时候有一种想当然,那就是在我脑海中的构图是两个链表逐渐合成一个的图。随想录的图是给出了两个独立的链表进行比较。 

如果两个链表的做法有交点,那两个链表自交点起的末尾一定是一样的那就可以把两个链表尾对其,然后然后从短的那个链表的头节点开始依次比对是否有地址相等的点,找得到就是有交点,反之则没有。

按照思路复现了一遍,学习到了swap可以对指针内容的交换。



 142.环形链表II  


随想录文字讲解:代码随想录 (programmercarl.com)

随想录视频讲解:把环形链表讲清楚! 如何判断环形链表?如何找到环形链表的入口? LeetCode:142.环形链表II_哔哩哔哩_bilibili

状态:没做出来


我只能通过快慢指针来判断循环链表,但是对如何寻找入口束手无策,讲解说的很明白,直接看讲解就行了


感觉今天写的很吃力,第四题属于是完全没有思路,应当多看看这道题。

  • 12
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值