【算法刷题】链表

文章目录


环形链表

判断是否有环

环形链表 是指链表中的某些节点的 next 指针指向了链表中的某个前面的节点,导致链表中的节点构成一个环。

思路:快慢指针(Floyd 判圈算法)

我们可以使用 快慢指针 来判断链表中是否有环。这种方法也叫做 Floyd 判圈算法,是一个经典且高效的解法。

​ • 快指针(slow pointer) 每次移动一步。

​ • 慢指针(fast pointer) 每次移动两步。

判断条件:

  1. 如果链表中没有环,快指针最终会遇到 null,这时候说明链表没有环。
  2. 如果链表有环,快指针和慢指针一定会相遇,因为快指针每次移动两步,而慢指针每次移动一步,快指针追得上慢指针。
java 复制代码
    // 判断 是否有环
    public boolean hasCycle(ListNode head) {
        ListNode slow = head;
        ListNode fast = head;
        while (fast != null && fast.next != null) {
            slow = slow.next;
            fast = fast.next.next;
            if (slow == fast) {
                return true;
            }
        }
        return false;
    }

找出环的入口位置

一旦我们知道链表有环,下一步就是 找到环的入口。这可以通过以下的步骤来实现:

思路:

​ 1. 判断环的存在:首先使用快慢指针来判断链表是否有环,如果没有环,则直接返回 null。

​ 2. 找到环的入口

​ • 假设链表有环,快慢指针在环内相遇。

​ • 将其中一个指针从头节点开始,另一个指针保持在相遇位置。

​ • 然后,两个指针同时每次移动一步。它们相遇的位置就是环的入口。

为什么能这么做?

​ • 假设链表总共有 n 个节点,其中前 k 个节点在环外,后 n-k 个节点在环内。

​ • 当快慢指针在环内相遇时,假设慢指针在环内相遇的位置是 X。

​ • 如果将其中一个指针移回链表的起点,并让两个指针同时移动,每次移动一步,它们必定会在环的入口相遇。

java 复制代码
public ListNode detectCycle(ListNode head) {
    ListNode slow = head;
    ListNode fast = head;

    // 1. 判断有没有环
    while (fast != null && fast.next != null) {
        slow = slow.next;
        fast = fast.next.next;

        if (slow == fast) { // 快慢指针相遇,说明有环
            break;
        }
    }

    // 如果没有环,直接返回 null
    if (fast == null || fast.next == null) {
        return null;
    }

    // 2. 找到环的入口
    fast = head; // 快指针移到链表头
    while (slow != fast) {
        slow = slow.next;
        fast = fast.next;
    }

    return slow; // 返回环的入口
}

双指针

反转链表(Reverse a Linked List)

反转链表是链表操作中最经典的题目之一,特别是在面试中经常出现。这个问题的基本要求是将链表的节点顺序反转。

基本思路:

使用三个指针来反转链表:

​ 1. prev:指向当前节点的前一个节点。

​ 2. cur:指向当前节点。

​ 3. next:指向当前节点的下一个节点。

我们遍历链表,将每个节点的 next 指针指向前一个节点。

java 复制代码
    public ListNode reverseList(ListNode head) {
        ListNode prev = null;
        ListNode curr = head;
        ListNode next = null;
        while (curr != null) {
            next = curr.next;
            curr.next = prev;
            prev = curr;
            curr = next;
        }
        
        return prev;
        
    }

移除链表中的指定元素(Remove Linked List Elements)

值得注意:移除元素需要保留该节点的前一个节点。

java 复制代码
    public ListNode removeElements(ListNode head, int val) {

        while (head != null && head.val == val) {
            head = head.next;
        }

        ListNode curr = head;
        ListNode prev = null;
        while (curr != null) {
            if (curr.val == val) {
                prev.next =curr.next;
                curr = prev.next;
            }else {
                prev = curr;
                curr = curr.next;
            }
            
        }
        return head;
    }

相关推荐
chao18984410 分钟前
基于MATLAB的ADI方法求解偏微分方程详解
开发语言·算法·matlab
智驱力人工智能15 分钟前
超越识别 将光学字符识别(OCR)技术转化为可靠业务能力的交付思维 光学字符识别 金融票据OCR识别系统 物流单据自动识别技术
人工智能·opencv·算法·目标检测·ocr·边缘计算
算法与编程之美25 分钟前
解决tensor的shape不为1,如何转移到CPU的问题
人工智能·python·深度学习·算法·机器学习
natide26 分钟前
词汇/表达差异-8-Token Overlap(词元重叠度)
大数据·人工智能·深度学习·算法·自然语言处理·nlp·知识图谱
hetao173383730 分钟前
2025-12-22 hetao1733837的笔记
c++·笔记·算法
云技纵横37 分钟前
Redis 数据结构底层与 Hash 优于 JSON 的工程实践
数据结构·redis·哈希算法
Binky67844 分钟前
力扣--贪心篇(1)
数据结构·算法·leetcode
sinat_255487811 小时前
文件I/O流
java·jvm·算法
北辰水墨1 小时前
【算法篇】单调栈的学习
c++·笔记·学习·算法·单调栈
源代码•宸1 小时前
goframe框架签到系统项目开发(分布式 ID 生成器、雪花算法、抽离业务逻辑到service层)
经验分享·分布式·mysql·算法·golang·雪花算法·goframe