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

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

题目链接:https://leetcode.cn/problems/swap-nodes-in-pairs/
视频讲解:https://www.bilibili.com/video/BV1YT411g7br/

题目描述:给你一个链表,两两交换其中相邻的节点,并返回交换后链表的头节点。你必须在不修改节点内部的值的情况下完成本题(即,只能进行节点交换)。

示例1:
输入:head = [1,2,3,4]
输出:[2,1,4,3]

示例2:
输入:head = []
输出:[]

示例3:
输入:head = [1]
输出:[1]

思路:先定义一个虚拟头结点,便于操作,1和2节点进行交换,如果直接将cur.next 指向cur.next.next,则会导致节点1丢失,节点3同理,因此在操作之前要将节点1和3提前保存。第二个关键点是循环结束的条件,题给条件是两两交换,当链表个数为偶数时,cur.next 为null时循环结束,当链表个数为奇数时,cur.next.nex为null时循环结束。
代码随想录算法训练营day04| LeetCode 24 两两交换链表中的节点 、LeetCode 19 删除链表的倒数第N个节点、面试题 02.07 链表相交、LeetCode 142.环形链表II_第1张图片

class Solution {
    public ListNode swapPairs(ListNode head) {
        ListNode dummyhead = new ListNode();//定义虚拟头结点
        dummyhead.next = head;// 将虚拟头结点指向head
        ListNode cur = dummyhead;
        ListNode temp;
        ListNode temp1;
        while(cur.next != null && cur.next.next != null){//循环结束条件
            temp = cur.next;
            temp1 = cur.next.next.next;//先将会丢失的元素保存
            cur.next = cur.next.next;//步骤一
            cur.next.next = temp;//步骤二
            temp.next = temp1;//步骤三
            cur = cur.next.next;//交换下一组元素
        }
        return dummyhead.next;
    }
}

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

题目链接:https://leetcode.cn/problems/remove-nth-node-from-end-of-list/
视频讲解:https://www.bilibili.com/video/BV1vW4y1U7Gf/

题目描述:给你一个链表,删除链表的倒数第 n 个结点,并且返回链表的头结点。

示例1:
输入:head = [1,2,3,4,5], n = 2
输出:[1,2,3,5]

示例2:
输入:head = [1], n = 1
输出:[]

示例3:
输入:head = [1,2], n = 1
输出:[1]

思路:首先是如何找到倒数第n个节点,先定义一个虚拟头结点(主要是便于我们对操作的元素是不是头结点不需要判断,可以采用统一的方法进行操作)。定义快慢指针,然后让快指针先移动n+1步,然后快慢指针再同时移动,直到快指针指向null,这时慢指针指向了要操作节点的前一个节点,就可以进行删除操作了。

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 = 0; i < n + 1; i++){// 将快指针先移动n+1步,使慢指针指向要删除节点的前一个节点
            fast = fast.next;
        }
        while(fast != null){//此时slow指向的是要删除节点的前一个节点
            fast = fast.next;
            slow = slow.next;
        }
        slow.next = slow.next.next;
        return dummyhead.next;
    }
}

面试题 02.07 链表相交(同LeetCode 160 相交链表)

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

题目描述:给你两个单链表的头节点 headA 和 headB ,请你找出并返回两个单链表相交的起始节点。如果两个链表没有交点,返回 null。

图示两个链表在节点 c1 开始相交:
代码随想录算法训练营day04| LeetCode 24 两两交换链表中的节点 、LeetCode 19 删除链表的倒数第N个节点、面试题 02.07 链表相交、LeetCode 142.环形链表II_第2张图片
题目数据 保证 整个链式结构中不存在环。
注意,函数返回结果后,链表必须 保持其原始结构 。

示例1:
代码随想录算法训练营day04| LeetCode 24 两两交换链表中的节点 、LeetCode 19 删除链表的倒数第N个节点、面试题 02.07 链表相交、LeetCode 142.环形链表II_第3张图片

输入:intersectVal = 8, listA = [4,1,8,4,5], listB = [5,0,1,8,4,5], skipA = 2, skipB = 3
输出:Intersected at ‘8’
解释:相交节点的值为 8 (注意,如果两个链表相交则不能为 0)。 从各自的表头开始算起,链表 A 为 [4,1,8,4,5],链表 B 为 [5,0,1,8,4,5]。 在 A 中,相交节点前有 2个节点;在 B 中,相交节点前有 3 个节点。

示例2:
代码随想录算法训练营day04| LeetCode 24 两两交换链表中的节点 、LeetCode 19 删除链表的倒数第N个节点、面试题 02.07 链表相交、LeetCode 142.环形链表II_第4张图片
输入:intersectVal = 2, listA = [0,9,1,2,4], listB = [3,2,4], skipA
= 3, skipB = 1
输出:Intersected at ‘2’
解释:相交节点的值为 2 (注意,如果两个链表相交则不能为 0)。 从各自的表头开始算起,链表 A 为 [0,9,1,2,4],链表 B 为 [3,2,4]。 在 A 中,相交节点前有 3 个节点;在 B
中,相交节点前有 1 个节点。

示例3:
代码随想录算法训练营day04| LeetCode 24 两两交换链表中的节点 、LeetCode 19 删除链表的倒数第N个节点、面试题 02.07 链表相交、LeetCode 142.环形链表II_第5张图片
输入:intersectVal = 0, listA = [2,6,4], listB = [1,5], skipA = 3,
skipB = 2 输出:null
解释:从各自的表头开始算起,链表 A 为 [2,6,4],链表 B 为 [1,5]。由于这两个链表不相交,所以 intersectVal 必须为 0,而 skipA 和 skipB 可以是任意值。 这两个链表不相交,因此返回null 。

public class Solution {
    public ListNode getIntersectionNode(ListNode headA, ListNode headB) {
        ListNode curA = headA;
        ListNode curB = headB;
        int lenA = 0,lenB = 0;
        while(curA != null){//求出链表A的长度
            lenA++;
            curA = curA.next;
        }
        while(curB != null){//求出链表B的长度
            lenB++;
            curB = curB.next;
        }
        curA = headA;
        curB = headB;
        if(lenB > lenA){// 让curA为最长链表的头,lenA为其长度
            int temp = lenA;
            lenA = lenB;
            lenB = temp;
            ListNode tempNode = curA;
            curA = curB;
            curB = tempNode;
        }
        //求长度差
        int gap = lenA - lenB;
        // 让curA和curB在同一起点上(末尾位置对齐)
        while(gap-- > 0){
            curA = curA.next;
        }
        // 遍历curA 和 curB,遇到相同则直接返回
        while(curA != null){
            if(curA == curB){
                return curA;
            }
            curA = curA.next;
            curB = curB.next;
        }
        return null;
    }
}

LeetCode 142 环形链表II

题目链接:https://leetcode.cn/problems/linked-list-cycle-ii/
视频讲解:https://www.bilibili.com/video/BV1if4y1d7ob/

题目描述:给定一个链表的头节点 head ,返回链表开始入环的第一个节点。 如果链表无环,则返回 null。
如果链表中有某个节点,可以通过连续跟踪 next 指针再次到达,则链表中存在环。 为了表示给定链表中的环,评测系统内部使用整数 pos来表示链表尾连接到链表中的位置(索引从 0 开始)。如果 pos 是 -1,则在该链表中没有环。注意:pos不作为参数进行传递,仅仅是为了标识链表的实际情况。不允许修改 链表。

示例1:
输入:head = [3,2,0,-4], pos = 1
输出:返回索引为 1 的链表节点
解释:链表中有一个环,其尾部连接到第二个节点。

示例2:
输入:head = [1,2], pos = 0
输出:返回索引为 0 的链表节点
解释:链表中有一个环,其尾部连接到第一个节点。

示例3:
输入:head = [1], pos = -1
输出:返回 null
解释:链表中没有环。

思路:用快慢指针相遇来判断是否有环,使用快慢指针法,分别定义 fast 和 slow 指针,从头结点出发,fast指针每次移动两个节点,slow指针每次移动一个节点,如果 fast 和 slow指针在途中相遇 ,说明这个链表有环。

那么为什么fast指针和slow指针一定会相遇呢?这是因为fast是走两步,slow是走一步,其实相对于slow来说,fast是一个节点一个节点的靠近slow的,所以fast一定可以和slow重合。
详见Carl哥的代码随想录142.环形链表II

public class Solution {
    public ListNode detectCycle(ListNode head) {
        ListNode fast = head;//定义快慢指针
        ListNode slow = head;
        while(fast != null && fast.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 index2;
            }
        }
        return null;
    }
}

总结:今天的题对我来说有点难度,自己想根本想不出来,代码虽然看懂了,但是自己写还是不会,过几天再来看看,加强印象,这四天确实学到了很多东西,继续加油!

你可能感兴趣的:(链表,leetcode,算法)