[豪の算法奇妙冒险] 代码随想录算法训练营第四天 | 24-两两交换链表中的节点、19-删除链表的倒数第N个节点、面试题02.07-链表相交、142-环形链表II

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


LeetCode24-两两交换链表中的节点

题目链接:https://leetcode.cn/problems/swap-nodes-in-pairs/description/

文章讲解:https://programmercarl.com/0024.两两交换链表中的节点.html

视频讲解:https://www.bilibili.com/video/BV1YT411g7br/?vd_source=b989f2b109eb3b17e8178154a7de7a51

​ 一拿到题目,我的思路是采用虚拟头节点保存Head的初始位置,先单独排除无元素和一个元素的情况,接着再单独处理两个元素的情况,之后如果符合条件再进行循环交换

​ 循环交换的时候,使用pre、cur和after三个指针遍历链表,进行cur和after所指节点的两两交换,关键在于确定何时停止循环和避免操作空指针

​ 总的来说还是要多画图、多分析

image-20251124092127596

class Solution {
    public ListNode swapPairs(ListNode head) {
        ListNode dummyHead = head;
        if(dummyHead == null || dummyHead.next == null){
            return dummyHead;
        }

        ListNode pre = null;
        ListNode cur = dummyHead;
        ListNode after = dummyHead.next;

        cur.next = after.next;
        after.next = cur;
        dummyHead = after;

        pre = cur;
        cur = cur.next;
        while(cur != null){
            after = cur.next;
            if(after == null){
                break;
            }

            pre.next = after;
            cur.next = after.next;
            after.next = cur;

            pre = cur;
            cur = cur.next;
        }
        return dummyHead;
    }
}

​ 看完Carl哥的讲解后,发现我的这个解法还能再活用dummyHead,进行逻辑的优化,统一操作链表,代码也更加简洁明了

image-20251124210232359

class Solution {
    public ListNode swapPairs(ListNode head) {
        ListNode dummyHead = new ListNode();
        dummyHead.next = head;
        ListNode cur = dummyHead;

        while(cur.next != null && cur.next.next != null){
            ListNode pre = cur.next;
            ListNode after = cur.next.next.next;

            cur.next = cur.next.next;
            cur.next.next = pre;
            pre.next = after;

            cur = cur.next.next;
        }

        return dummyHead.next;
    }
}

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

题目链接:https://leetcode.cn/problems/remove-nth-node-from-end-of-list/description/

文章讲解:https://programmercarl.com/0019.删除链表的倒数第N个节点.html

视频讲解:https://www.bilibili.com/video/BV1vW4y1U7Gf/?vd_source=b989f2b109eb3b17e8178154a7de7a51

​ 采用快慢指针的思想解,快指针从dummyHead出发,先往后移动 n+1 步,然后快慢指针一起往后移动,直到快指针指向null,此时慢指针指向的是要删除的节点的前一个节点

image-20251124211822387

class Solution {
    public ListNode removeNthFromEnd(ListNode head, int n) {
        ListNode dummyHead = new ListNode();
        dummyHead.next = head;
        ListNode fast = dummyHead;
        ListNode slow = dummyHead;

        for(int i = 1;i <= n+1;i++){
            fast = fast.next;
        }

        while(fast != null){
            fast = fast.next;
            slow = slow.next;
        }

        slow.next = slow.next.next;
        
        return dummyHead.next;
    }
}

面试题02.07 链表相交

题目链接:https://leetcode.cn/problems/intersection-of-two-linked-lists-lcci/description/

文章讲解:https://programmercarl.com/面试题02.07.链表相交.html

​ 拿到题第一眼想到的是双重for循环暴力解,注意单个节点的情况,劈里啪啦写完发现居然能过,但这份代码一点也不优雅,而且时间复杂度来到O(n^2),得改!

image-20251124215047231

public class Solution {
    public ListNode getIntersectionNode(ListNode headA, ListNode headB) {

        if(headA == headB){
            return headA;
        }

        for(ListNode pA = headA; pA != null; pA = pA.next){
            for(ListNode pB = headB; pB != null; pB = pB.next){
                if(pA == pB){
                    return pA;
                }
            }
        }

        return null;
    }
}

​ 看了题解后自己又写了一遍,大开眼界:可以先求出AB两个链表的长度,然后求出两个链表长度差值,让两个链表的末尾对齐,curA和curB对齐相对短的那一个,然后比较curA和curB是否相同,不同则同时往后移动curA和curB,如果遇到相同的情况则找到了交点,否则返回null。妙呀妙呀!

image-20251124220719855

public class Solution {
    public ListNode getIntersectionNode(ListNode headA, ListNode headB) {
        ListNode curA = headA;
        ListNode curB = headB;
        int lengthA = 1;
        int lengthB = 1;

        while(curA != null){
            curA = curA.next;
            lengthA++;
        }
        while(curB != null){
            curB = curB.next;
            lengthB++;
        }

        curA = headA;
        curB = headB;
        if(lengthA >= lengthB){
            for(int i = 1;i <= lengthA - lengthB;i++){
                curA = curA.next;
            }
        }else{
            for(int i = 1;i <= lengthB - lengthA;i++){
                curB = curB.next;
            }
        }

        while(curA != null){
            if(curA == curB){
                return curA;
            }
            curA = curA.next;
            curB = curB.next;
        }

        return null;
    }
}

LeetCode142 环形链表II

题目链接:https://leetcode.cn/problems/linked-list-cycle-ii/description/

文章讲解:https://programmercarl.com/0142.环形链表II.html

视频讲解:https://www.bilibili.com/video/BV1if4y1d7ob/?vd_source=b989f2b109eb3b17e8178154a7de7a51

​ 这题解法相当的妙呀,先定义一个快指针和一个慢指针,快指针每次往后走两个节点,慢指针每次往后走一个节点,它们如果相遇则说明链表存在环

​ 接着,由数学推理可以得出,从head到环入口的距离 = (n-1)圈环的距离 + 快慢指针相遇点到环入口的距离

​ 由此可以再定义index1从快慢指针相遇点出发,index2从head出发,它们都每次往后走一个节点,这样index1和index2相遇的节点即为环的入口节点

image-20251124223024764

public class Solution {
    public ListNode detectCycle(ListNode head) {
        ListNode fast = head;
        ListNode slow = head;

        while(fast != null && fast.next != null && fast.next.next != null){
            fast = fast.next.next;
            slow = slow.next;
            if(fast == slow){
                ListNode index1 = fast;
                ListNode index2 = head;
                while(index1 != index2){
                    index1 = index1.next;
                    index2 = index2.next;
                }
                return index1;
            }
        }

        return null;
    }
}
posted @ 2025-11-24 22:36  SchwarzShu  阅读(0)  评论(0)    收藏  举报