代码随想录训练营Day 04 | 链表Part 02(8.31)

目录

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

题目分析:

 代码:

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

解题思路

参考代码(源于代码随想录官网)

面试题 02.07. 链表相交

题目分析

参考代码

142.环形链表II

解题思路

参考代码


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

题目分析:

这一题,我认为它的难点就在于如何去调整链表之间的关系,以及要设置多个临时变量才存储,感觉是“双指针”的高级应用了。

但是即使是理解了代码的思路,在写代码的时候也会有新的问题,例如是要用while来遍历还是要以for或者if等进行判断等操作,以及一些next域的不断套用,会导致思路上的混乱,这个时候还是要多去捋几遍。还有一个就是循环条件是什么?循环结束时还需不需要进行其他的操作,例如销毁,释放空间,或者是考虑要返回的是什么节点?这些都需要多考虑一下,以免报错。

下面给的代码在力扣网上是测试通过的,但是漏了一个,没有给虚拟头节点进行空间的释放操作。

 代码:

class Solution {
public:
    ListNode* swapPairs(ListNode* head) {
        ListNode *linshi = new ListNode(0);
        linshi->next = head;
        ListNode *cur = linshi;
        while(cur->next != NULL && cur->next->next != NULL) {
            ListNode *t1 = cur->next;
            ListNode *t2 = cur->next->next->next;
            cur->next = cur->next->next;
            cur->next->next = t1;
            t1->next = t2;

            cur = cur->next->next;
        }
        return linshi->next;
    }
};

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

解题思路

这题又又又用到了双指针——快慢指针的使用,主要是注意题目已经提及是“倒数”,所以需要遍历到最后一个节点,然后依次往前推,那么如果使用了两个指针,就直接控制好两个指针之间的间隔,然后同时往后遍历,直到快指针所指向的节点为NULL时才停止移动,而这一题还有一点需要注意的就是我们删除节点的相关操作,一定要指向前一个节点,也就是我们在这一题中需要让间隔大1,或者是快指针先走一步,否则在删除节点的时候会出错,这一题的代码直接引用代码随想录上的参考代码,不再另行列出,主要还是理解思路。

参考代码(源于代码随想录官网)

class Solution {
public:
    ListNode* removeNthFromEnd(ListNode* head, int n) {
        ListNode* dummyHead = new ListNode(0);
        dummyHead->next = head;
        ListNode* slow = dummyHead;
        ListNode* fast = dummyHead;
        while(n-- && fast != NULL) {
            fast = fast->next;
        }
        fast = fast->next; // fast再提前走一步,因为需要让slow指向删除节点的上一个节点
        while (fast != NULL) {
            fast = fast->next;
            slow = slow->next;
        }
        slow->next = slow->next->next; 
        return dummyHead->next;
    }
};

面试题 02.07. 链表相交

题目分析

这一题其实我感觉在理解了题目的意思之后难度其实并不是很大,但也需要一定的理解。

注意一下题目的相关提示,在该题目的提示中,存在一条:“两个链表的最终节点始终相同,一旦他们相交,之后的所有节点将相等”,这也符合上了该题的参考代码了。

所以这一题的解题思路主要就是先判断一下两个链表的长度,然后将两个链表“右对齐”,也就是将尾端对齐,然后将两个指针分别放在对齐处的位置,同时向后遍历,因为抓住“一旦相交,之后的所有节点将相等”,所以就比较容易能得解了。

参考代码

class Solution {
public:
    ListNode *getIntersectionNode(ListNode *headA, ListNode *headB) {
        ListNode *ca = headA;
        ListNode *cb = headB;
        int la = 0;
        int lb = 0;
        while(ca != NULL) {
            la++;
            ca = ca->next;
        }
        while(cb != NULL) {
            lb++;
            cb = cb->next;
        }
        ca = headA;
        cb = headB;
        if(lb > la) {
            swap(la,lb);
            swap(ca,cb);//交换
        }
        int l = la - lb;
        while(l){
            ca = ca->next;
            l--;
        }
        while(ca != NULL) {
            if(ca == cb) {
                return ca;
            }
            ca = ca->next;
            cb = cb->next;
        }
        return NULL;
    }
};

142.环形链表II

解题思路

这一题的思考过程还是有点难度的,感觉稍稍运用到了一点物理知识,经过一番理解过后还有点蒙圈,终究是需要多想几遍。

最详细的过程还是推荐大家到代码随想录上看老师的讲解,因为配有动画,理解起来肯定更为方便,文章链接:代码随想录 (programmercarl.com)icon-default.png?t=N7T8https://programmercarl.com/0142.%E7%8E%AF%E5%BD%A2%E9%93%BE%E8%A1%A8II.html#%E7%AE%97%E6%B3%95%E5%85%AC%E5%BC%80%E8%AF%BE

以下为我的个人理解:

首先要找到的是两个环的环的入口,可以假设一下有几种情况,①不存在环,也就是只有一条单链表;②不存在环,是一个单独的节点;③存在环,正好围成一个圈;④存在环,但不单单只是一个圈,会多出若干个节点为链,如下图所示。

而本题要进行解答,应该也是分成两个部分来进行判断,简单点说,就是如果判断过程中得知存在环,就直接返回了。

因此,这一题其实还是借用到了“双指针法”。而这一题的双指针,和上面的链表相交我认为有一点相似,也是快慢指针找相遇点,这一题也是先让一个快指针入环,接着慢指针入环,感觉有点物理上相对速度的那种味道,当两个指针在一个环内不断地走,以不同的速度,他们必定相遇。这一点理解起来并不难,我感觉对我来说难点是我该如何找到他们两的入口,因为两个指针入环的时间肯定是不一样的,他们可以转了n圈以后相遇,我应该如何去判断?而这一切都可以通过相关的数学证明,最好是画图,也就能理解了。

参考代码

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;
            // 快慢指针相遇,此时从head 和 相遇点,同时查找直至相遇
            if (slow == fast) {
                ListNode* index1 = fast;
                ListNode* index2 = head;
                while (index1 != index2) {
                    index1 = index1->next;
                    index2 = index2->next;
                }
                return index2; // 返回环的入口
            }
        }
        return NULL;
    }
};
  • 16
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值