链表一些基础题目的学习

链表

参考链接

一、理论基础

单链表
链表是一种通过 指针串联在一起的线性结构,每一个结点由两部分组成, 一个是数据域,一个是指针域(存放指向下一个结点的 指针),最后一个结点的指针域指向null。
单链表示意图:


链表的入口节点称为链表的头结点也就是head。

双链表
每一个结点有2个指针域,分别 指向上一个结点和下一个结点。因此,它既可以向前查询也可以向后查询。
双链表示意图

循环链表
顾名思义,就是 链表首尾相连
循环链表示意图


循环链表可以用来解决约瑟夫问题

约瑟夫问题 < = = > <==> <==> 丢手绢 < = = > <==> <==> 约瑟夫环
有n个人围成一圈,从第一个人开始报数,报到m的人出圈,剩下的人继续从1开始报数,直到剩下最后一个人。求出最后一个出圈的人的编号。

链表的存储方式

链表中的节点在内存中不是连续分布的,而是散乱分布在内存中的某地址上。分配机制取决于操作系统的内存管理。

链表的删除

链表的添加

链表的定义

Java:

public class ListNode {
    int val;
    ListNode next;

    public ListNode() {
    }

    public ListNode(int val) {
        this.val = val;
    }

    public ListNode(int val, ListNode next) {
        this.val = val;
        this.next = next;
    }
}

JavaScript

class ListNode {
    val;
    next = null;
    constructor(value) {
        this.val = value;
        this.next = null;
    }
}

Python

class ListNode:
    def __init__(self, val, next=None):
        self.val = val
        self.next = next

二、实践

203.移除链表元素

力扣链接
给你一个链表的头节点 head 和一个整数 val ,请你删除链表中所有满足 Node.val == val 的节点,并返回 新的头节点 。

示例 1:

	输入:head = [1,2,6,3,4,5,6], val = 6
	输出:[1,2,3,4,5]

示例2:

	输入:head = [], val = 1
	输出:[]

示例3:

输入:head = [7,7,7,7], val = 7
输出:[]

提示:

  • 列表中的节点数目在范围[0, 1 0 4 10^4 104]内
  • 1 <= Node.val <= 50
  • 0 <= val <= 50

Java代码如下:

class Solution{
    public ListNode removeElements(ListNode head, int val) {
       /**设置一个虚拟头结点(指向头结点head):不用单独把头结点摘出来考虑*/
       ListNode dummyHead = new ListNode(-1, head);
       ListNode cur = dummyHead;
       while (cur.next != null) {
           if (cur.next.val == val) {
               cur.next = cur.next.next;
           } else {
               cur = cur.next;
           }
       }
       return dummyHead.next;
    }

    /**
     * 不设置虚拟头结点,将头结点和其他节点分别考虑
     */
    public ListNode removeElementsSimple(ListNode head, int val) {
        /**注意这里不是if啊! 将符合和即将符合条件的头结点全部去除*/
        while (head != null && head.val == val) {
            head = head.next;
        }
        /**处理其他结点*/
        ListNode cur = head;
        while (cur != null && cur.next != null) {
            if (cur.next.val == val) {
                cur.next = cur.next.next;
            } else {
                cur = cur.next;
            }
        }
        return head;
    }

    /**
     * 通过递归去实现
     */
    public ListNode removeElementsRecursive(ListNode head, int val) {
        if (head == null) {
            return null;
        }
        head.next = removeElementsRecursive(head.next, val);
        return head.val == val ? head.next : head;
    }
}

JavaScript代码如下:

/**
 * @param {ListNode} head
 * @param {number} val
 * @return {ListNode}
 */
var removeElements = function(head, val) {
    // 1.
    // while (head !== null && head.val === val) {
    //     head = head.next;
    // }
    // let cur = head;
    // while (cur !== null && cur.next !== null) {
    //     if (cur.next.val === val) {
    //         cur.next = cur.next.next;
    //     } else {
    //         cur = cur.next;
    //     }
    // }
    // return head;

    // 2.
    // let dummyHead = new ListNode(-1, head);
    // let cur = dummyHead;
    // while (cur !== null && cur.next !== null) {
    //     if (cur.next.val === val) {
    //         cur.next = cur.next.next;
    //     } else {
    //         cur = cur.next;
    //     }
    // }
    // return dummyHead.next;

    // 3.
    if (head == null) {
        return null;
    }
    head.next = removeElements(head.next, val);
    return head.val == val ? head.next : head;

};

Python代码如下:

class Solution:
    def removeElements(self, head: Optional[ListNode], val: int) -> Optional[ListNode]:
        # 1.
        # while head and head.val == val:
        #     head = head.next
        # cur = head
        # while cur and cur.next:
        #     if cur.next.val == val:
        #         cur.next = cur.next.next
        #     else:
        #         cur = cur.next
        # return head

        # 2.
        # dummyHead = ListNode(-1, head)
        # cur = dummyHead
        # while cur and cur.next:
        #     if cur.next.val == val:
        #         cur.next = cur.next.next
        #     else:
        #         cur = cur.next
        # return dummyHead.next

        # 3.
        if not head:
            return
        head.next = self.removeElements(head.next, val)
        return head.next if head.val == val else head

206. 反转链表

力扣链接
给你单链表的头节点 head ,请你反转链表,并返回反转后的链表。
示例1:

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

示例2:

	输入:head = [1,2]
	输出:[2,1]

示例3:

	输入:head = []
	输出:[]

提示:

  • 链表中节点的数目范围是 [0, 5000]
  • -5000 <= Node.val <= 5000

Java代码如下(3种方法):

class Solution{
    public ListNode reverseList(ListNode head) {
        /*// 2.递归法
        return reverse(null, head);*/

        // 3.头插法
        ListNode dummyHead = new ListNode(-1);
        ListNode cur = head;
        // 定义temp:保存当前结点的next指针指向
        ListNode temp = null;
        // 遍历所有结点
        while (cur != null) {
            temp = cur.next;
            cur.next = dummyHead.next;
            dummyHead.next = cur;
            cur = temp;
        }
        return dummyHead.next;
    }

    private ListNode reverse(ListNode prev, ListNode cur) {
        if (cur == null) {
            return prev;
        }
        // 定义temp结点: 保存cur指针更新前的指向结点
        ListNode temp = cur.next;
        // 翻转指针
        cur.next = prev;
        return reverse(cur, temp);
    }

    public ListNode reverseListByDoublePoint(ListNode head) {

        // 1.双指针法
        ListNode cur = head;
        ListNode prev = null;
        ListNode temp = null;
        while (cur != null) {
            // 保存next指针改变前要指向的结点
            temp = cur.next;
            // 翻转指向
            cur.next = prev;
            // 更新
            prev = cur;
            // 更新
            cur = temp;
        }
        return prev;
    }
}

JavaScript代码如下:

/**
 * @param {ListNode} head
 * @return {ListNode}
 */
let reverseList = function (head) {
    /*// 2.递归法
    return reverse(null, head);*/

    // 3.头插法
    let dummyHead = new ListNode(-1);
    dummyHead.next = null;
    let temp = null, cur = head;
    while (cur) {
        temp = cur.next;
        cur.next = dummyHead.next;
        dummyHead.next = cur;
        cur = temp;
    }
    return dummyHead.next;
}

let reverse = function (prev, cur) {
    if (!cur) {
        return prev;
    }
    let temp = cur.next;
    cur.next = prev;
    return reverse(cur, temp);
}

let reverseListDoublePoint = function (head) {
    // 1.双指针法
    let cur = head,
        prev = null,
        temp = null;
    while (cur) {
        temp = cur.next;
        cur.next = prev;
        prev = cur;
        cur = temp;
    }
    return prev;
};

Python代码如下:

# Definition for singly-linked list.
# class ListNode:
#     def __init__(self, val=0, next=None):
#         self.val = val
#         self.next = next
class Solution:
    def reverseList(self, head: Optional[ListNode]) -> Optional[ListNode]:
        '''# 2.递归法
        return self.reverse(None, head)'''

        # 3.头插法
        dummyHead = ListNode()
        cur, temp = head, None
        while cur:
            temp = cur.next
            cur.next = dummyHead.next
            dummyHead.next = cur
            cur = temp
        return dummyHead.next
    
    def reverse(self, prev, cur):
        if not cur:
            return prev
        temp = cur.next
        cur.next = prev
        return self.reverse(cur, temp)
        
    def reverseListDoublePoint(self, head):
        # 1.双指针
        cur, prev, temp = head, None, None
        while cur:
            temp = cur.next
            cur.next = prev
            prev = cur
            cur = temp
        return prev

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

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

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

示例2:

	输入:head = []
	输出:[]

示例3:

	输入:head = [1]
	输出:[1]

提示:

  • 链表中节点的数目在范围 [0, 100] 内
  • 0 <= Node.val <= 100

Java代码如下:

class Solution {
    /**
     * @param head
     * @return ListNode
     * @Description: 方法二:递归
     * @Author ami168cc@163.com
     * @CreateTime 2023/6/11 14:25
     */
    public ListNode swapPairs(ListNode head) {
        if (head == null || head.next == null) {
            return head;
        }
        ListNode secondNode = head.next;
        ListNode ThirdNode = swapPairs(secondNode.next);
        /**第1个结点指向第3个结点*/
        head.next = ThirdNode;
        /**第2个结点指向第1个结点*/
        secondNode.next = head;

        return secondNode;
    }

    /**
     * @param head
     * @return ListNode
     * @Description: 方法一:使用虚拟头结点 + 循环
     * @Author ami168cc@163.com
     * @CreateTime 2023/6/11 14:01
     */
    public ListNode swapPairsMethodOne(ListNode head) {
        ListNode dummyHead = new ListNode(-1, head);
        ListNode cur = dummyHead;
        ListNode firstNode;
        while (cur.next != null && cur.next.next != null) {
            /**通过第一个和第二个结点均为非null,可以排除奇数结点情况下的最后一个结点的处理
             * 1.将第2个结点挂到虚拟头结点后面
             * 2.将第2个结点的后继结点(第3个结点)挂到第1个结点后面
             * 3.将第1个结点挂到第2个结点后面
             * 备注: 也可以将第2步和第3步顺序颠倒
             * */
            firstNode = cur.next;
            cur.next = cur.next.next;
            firstNode.next = cur.next.next;
            cur.next.next = firstNode;

            /**步长为2*/
            cur = cur.next.next;
        }
        return cur.next;
    }
}

JavaScript代码如下:

/**
 * @param {ListNode} head
 * @return {ListNode}
 */
let swapPairs = function (head) {
    // 2.递归
    if (!head || !head.next) {
        return head;
    }
    let secondNode = head.next,
        thirdNode = swapPairs(secondNode.next) || null;

    head.next = thirdNode;
    secondNode.next = head;

    return secondNode;
}

let swapPairsMethodOne = function (head) {
    // 1.虚拟头结点 + 循环
    let dummyHead = new ListNode(-1);
    dummyHead.next = head;
    let cur = dummyHead,
        firstNode = null;

    while (cur.next && cur.next.next) {
        firstNode = cur.next;

        cur.next = cur.next.next;
        firstNode.next = cur.next.next;
        cur.next.next = firstNode;

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

**Python代码如下: **

# Definition for singly-linked list.
# class ListNode:
#     def __init__(self, val=0, next=None):
#         self.val = val
#         self.next = next
class Solution:
    def swapPairs(self, head: Optional[ListNode]) -> Optional[ListNode]:
        # 2. 递归
        if not head or not head.next:
            return head
        secondNode = head.next
        thirdNode = self.swapPairs(secondNode.next)
        
        head.next = thirdNode
        secondNode.next = head

        return secondNode

    def swapPairsMethodOne(self, head: Optional[ListNode]) -> Optional[ListNode]:
        # 1. 虚拟头结点 + 循环
        dummyHead = ListNode(-1, head)
        cur, firstNode = dummyHead, None

        while cur.next and cur.next.next:
            firstNode = cur.next

            cur.next = cur.next.next
            firstNode.next = cur.next.next
            cur.next.next = firstNode

            # 步长为2
            cur = cur.next.next
        return dummyHead.next

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

力扣链接
给你一个链表,删除链表的倒数第 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]
思路如图:
![在这里插入图片描述](https://img-blog.csdnimg.cn/01568944853b4cd1b2cabe4623b3077a.png#pic_center)

Java代码如下:

public ListNode removeNthFromEnd(ListNode head, int n) {
    /**
     * 关键:怎么去找到倒数第N个结点呢(很难受,并不是找指定的值),
     * 思路:使用快慢双指针: 首先,快指针单独移动N次;其次,双指针一起移动,直到快指针==NULL,那么慢指针就指向倒数第N个结点了
     * 但是,题目是要删除它,而不是找到它,因此呢,我们要去找到它的前驱结点
     * 那么,就可以将快指针先移动N+1次,这样当快指针==NULL时,慢指针就指向它的前驱结点了。
     * */
    ListNode dummyHead = new ListNode(-1, head);
    ListNode fastNode = dummyHead;
    ListNode slowNode = dummyHead;

    /**快指针先移动N+1次*/
    for (int i = 0; i < n + 1; i++) {
        fastNode = fastNode.next;
    }

    while (fastNode != null) {
        fastNode = fastNode.next;
        slowNode = slowNode.next;
    }

    slowNode.next = slowNode.next.next;

    return dummyHead.next;
}

JavaScript代码如下:

/**
 * Definition for singly-linked list.
 * function ListNode(val, next) {
 *     this.val = (val===undefined ? 0 : val)
 *     this.next = (next===undefined ? null : next)
 * }
 */
/**
 * @param {ListNode} head
 * @param {number} n
 * @return {ListNode}
 */
var removeNthFromEnd = function(head, n) {
    let dummyHead = new ListNode(-1, head);
    let fastNode = slowNode = dummyHead;

    for (let i = 0; i < n + 1; i++) {
        fastNode = fastNode.next;
    }

    while (fastNode != null) {
        fastNode = fastNode.next;
        slowNode = slowNode.next;
    }

    slowNode.next = slowNode.next.next;

    return dummyHead.next;
};

Python代码如下:

class Solution:
    def removeNthFromEnd(self, head: Optional[ListNode], n: int) -> Optional[ListNode]:
        dummyHead = ListNode(-1, head)
        fastNode = slowNode = dummyHead

        for i in range(n + 1):
            fastNode = fastNode.next
        
        while fastNode != None:
            fastNode = fastNode.next
            slowNode = slowNode.next
        
        slowNode.next = slowNode.next.next

        return dummyHead.next

面试题 02.07. 链表相交

力扣链接
给你两个单链表的头节点 headA 和 headB ,请你找出并返回两个单链表相交的起始节点。如果两个链表没有交点,返回 null 。

图示两个链表在节点 c1 开始相交:

题目数据 保证 整个链式结构中不存在环

注意,函数返回结果后,链表必须 保持其原始结构

示例1:
在这里插入图片描述

	输入: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:
在这里插入图片描述

	输入: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:
在这里插入图片描述

	输入: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 。

提示:

  • listA 中节点数目为 m
  • listB 中节点数目为 n
  • 0 <= m, n <= 3 * 104
  • 1 <= Node.val <= 105
  • 0 <= skipA <= m
  • 0 <= skipB <= n
  • 如果 listA 和 listB 没有交点,intersectVal 为 0
  • 如果 listA 和 listB 有交点,intersectVal == listA[skipA + 1] == listB[skipB + 1]

思路:双指针
方法一:

  • 如果2个链表相交,即有公共长度。那么假设链表A的长度为m,链表B的长度为n;A中不相交部分的长度为a,B中不相交部分的长度为b,二者相交部分的长度均为c。则有a + c = m, b + c = n。
    • 如果 a==b, 那么双指针会同时到达相交部分。
    • 如果 a!=b,那么双指针都会遍历完对应的链表,当它们各自遍历完成后,便将hA指向链表B的头结点,hB指向链表A的头结点,则当hA再遍历b次,hB再遍历a次,二者一定会同时到达相交部分,即 a + c + b = b + c + a
  • 如果2个链表未相交,
    • 二者中至少有1个是为空链表,则返回null
    • 当二者均非空链表,则当hA遍历完链表B,hB遍历完链表A,即 m + n == n + m后,二者均指向null,则返回null

在这里插入图片描述
方法二:
通过移动较长链表的指针,使二者可以同时到达彼此链表的末尾。如果在同时移动过程中,二者指针相同,则返回指针;否则,返回null。
在这里插入图片描述

Java代码如下:

public class Solution {
    public ListNode getIntersectionNode(ListNode headA, ListNode headB) {
        // 方法1:
        if (headA == null || headB == null) {
            return null;
        }

        ListNode hA = headA, hB = headB;
        // 比较的是指针,并不是节点内容。
        while (hA != hB) {
            hA = hA == null ? headB : hA.next;
            hB = hB == null ? headA : hB.next;
        }
        return hA;
    }
	public ListNode getIntersectionNodeMethodTwo(ListNode headA, ListNode headB) {
       // 方法2: 既然相交部分结点相同,
       // 那么使hA指向结点和hB指向结点距离相交结点的距离相同
       // 则当二者指针相同,便是相交结点
       ListNode hA = headA, hB = headB;
       int lenA = 0, lenB = 0;
       while (hA != null) {
           lenA++;
           hA = hA.next;
       }
       while (hB != null) {
           lenB++;
           hB = hB.next;
       }

       // 这里一定要注意: 因为hA和hB已经指向null
       hA = headA;
       hB = headB;


       // 确保hA指向最长链表
       if (lenA < lenB) {
           int temp = lenA;
           lenA = lenB;
           lenB = temp;
           ListNode tempL = hA;
           hA = hB;
           hB = tempL;
       }

       // 将hA移动到可以使其与hB共同到达的位置
       int gap = lenA - lenB;
       while (gap-- > 0) {
           hA = hA.next;
       }

       // 寻找指针相同,不是内容相同
       while (hA != hB) {
           hA = hA.next;
           hB = hB.next;
       }
       // 找到,hA即指向相交结点;未找到,hA指向null
       return hA;
	}
}

**JavaScript代码如下: **

var getIntersectionNode = function(headA, headB) {
    // // 1
    // if (!headA || !headB) return null;

    // let hA =headA, hB = headB;
    // while (hA != hB) {
    //     hA = hA == null ? headB : hA.next;
    //     hB = hB == null ? headA : hB.next;
    // }
    // return hA;

    // 2
    let hA =headA, hB = headB,
        lenA = 0, lenB = 0;
    while (hA) {
        lenA++;
        hA = hA.next;
    }
    while (hB) {
        lenB++;
        hB = hB.next;
    }

    // 复原
    hA = lenA < lenB ? headB : headA;
    hB = lenA < lenB ? headA : headB;

    // 保证hA指向最长的链表
    if (lenA < lenB) {
        let temp = lenA;
        lenA = lenB;
        lenB = temp;
    }

     console.log(hA, hB);
    // 使hA指向长度等于hB的结点,保证二者同时到达相交结点。
    let gap = lenA - lenB;
    while (gap-- > 0) {
        hA = hA.next;
    }

    // 寻找相交结点
    while (hA != hB) {
        hA = hA.next;
        hB = hB.next;
    }
    return hA;
};

Python代码如下:

class Solution:
    def getIntersectionNode(self, headA: ListNode, headB: ListNode) -> ListNode:
        # 2
        hA, hB = headA, headB
        lenA = lenB = 0
        while hA:
            lenA += 1
            hA = hA.next
        while hB:
            lenB += 1
            hB = hB.next

        hA = headB if lenA < lenB else headA
        hB = headA if lenA < lenB else headB
        if lenA < lenB:
            lenA, lenB = lenB, lenA
        
        gap = lenA - lenB
        while gap > 0:
            hA = hA.next
            gap -= 1
        
        while hA != hB:
            hA = hA.next
            hB = hB.next
        
        return hA
        
        # # 1
        # if not headA or not headB:
        #     return None

        # hA, hB = headA, headB
        # while hA != hB:
        #     hA = headB if not hA else hA.next
        #     hB = headA if not hB else hB.next

        # return hA

142. 环形链表 II

力扣链接
给定一个链表的头节点 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
	解释:链表中没有环。

提示:

  • 链表中节点的数目范围在范围 [0, 104] 内
  • -105 <= Node.val <= 105
  • pos 的值为 -1 或者链表中的一个有效索引

在这里插入图片描述
**Java代码如下: **

    /**
     * 方法1: 快慢指针
     * @param head
     * @return
     */
    public ListNode detectCycle(ListNode head) {
        if (head == null || head.next == null) {
            return null;
        }
        ListNode slow = head;
        ListNode fast = head;
        while (fast != null && fast.next != null) {
            fast = fast.next.next;
            slow = slow.next;

            /**快慢指针相遇*/
            if (fast == slow) {
                /*将慢指针移到头结点,二者同时前进,再次相遇,便为所求*/
                slow = head;
                while (fast != slow) {
                    fast = fast.next;
                    slow = slow.next;
                }
                return fast;
            }
        }
        return null;

    }

    /**
     * 方法2: 哈希表
     * @param head
     * @return
     */
    public ListNode detectCycleM2(ListNode head) {
        HashSet<ListNode> visited = new HashSet<>();
        ListNode cur = head;
        while (cur != null) {
            if (visited.contains(cur)) {
                return cur;
            }
            visited.add(cur);
            cur = cur.next;
        }
        return null;
    }

JavaScript代码如下:

/**
 * 方法1: 哈希表
 * @param {ListNode} head
 * @return {ListNode}
 */
let detectCycle = function(head) {
    let visited = new Set(),
        cur = head;
    while (cur) {
        if (visited.has(cur)) {
            return cur;
        }
        visited.add(cur);
        cur = cur.next;
    }
    return null;
};

/**
 * 方法2: 快慢指针
 * @param head
 * @returns {null|*}
 */
let detectCycleM2 = function(head) {
    if (!head || !head.next) {
        return null;
    }
    let slow = head,
        fast = head;
    while (fast && fast.next) {
        fast = fast.next.next;
        slow = slow.next;

        if (slow == fast) {
            slow = head;
            while (slow != fast) {
                slow = slow.next;
                fast = fast.next;
            }
            return fast;
        }
    }

    return null;
};

Python代码如下:

class Solution:
    def detectCycle(self, head: Optional[ListNode]) -> Optional[ListNode]:
        # 1. 哈希表
        visited = set()
        cur = head
        while cur:
            if cur in visited:
                return cur
            visited.add(cur)
            cur = cur.next
        return None
    

    def detectCycleM2(self, head: Optional[ListNode]) -> Optional[ListNode]:
        if not head or not head.next:
            return
        slow = fast = head

        while fast and fast.next:
            fast = fast.next.next
            slow = slow.next
            if slow == fast:
                slow = head
                while fast != slow:
                    fast = fast.next
                    slow = slow.next
                return fast
        return
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值