数据结构--链表刷题(一)快慢指针

1.快慢指针

先看一道简单的题目:返回中间结点

这道题有一个最朴素的做法就是先遍历一边链表,设置计数器求出链表长度,再重新走1/2的链表长度,即可返回中间节点

java 复制代码
        // 第二种解法  
        //这种解法需要遍历两次链表
        ListNode cur1 = head;
        int cnt = 0;

        while(cur1 != null) {
            cnt++;
            cur1 = cur1.next;
        }

        ListNode cur2 = head;
        cnt = cnt/2;
        while(cnt != 0) {
            cur2 = cur2.next;
            cnt--;
        }

        return cur2;

但是这种方式有个明显的缺陷,就是你实际上是遍历了两遍链表,那有没有只遍历一次链表就能获得中间结点的方法呢?答案是有的,利用快慢指针

java 复制代码
// 第一种解法  只需遍历一次链表
        ListNode slow = head,fast = head;

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

        return slow;

快慢指针的核心思想其实是一种数学问题,即在相同时间内,路程之比就是速度之比

「力扣」第 19 题: 倒数第 k 个结点

https://leetcode.cn/problems/remove-nth-node-from-end-of-list/

java 复制代码
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 > 0) {
            fast = fast.next;
            n--;
        }

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

一个小细节:如果不使用虚拟头节点 在删除头节点的过程中会出错

2.判断是否带环

https://leetcode.cn/problems/linked-list-cycle/description/

代码实现:

1.快慢指针

java 复制代码
public class Solution {
    public boolean hasCycle(ListNode head) {
        if(head == null || head.next == null) return false;

        ListNode fast = head;
        ListNode slow = head;

        // 只要有环 则fast和slow一定会相遇
        while(fast != null && fast.next != null) {
            fast = fast.next.next;
            slow = slow.next;

            if(fast == slow) return true;
        }

        return false;
        
    }
}

2.使用哈希表

java 复制代码
public class Solution {
    public boolean hasCycle(ListNode head) {
        Set<ListNode> seen = new HashSet<ListNode>();
        while(head != null) {
            if(!seen.add(head)) {
                return true;
            }

            head = head.next;
        }

        return false;
        
    }
}

2.环形链表的进阶

https://leetcode.cn/problems/linked-list-cycle-ii/submissions/

代码实现:

java 复制代码
1.哈希表的实现
public class Solution {
    public ListNode detectCycle(ListNode head) {
        ListNode cur = head;
        Set<ListNode> seen = new HashSet<>();

        while(cur != null) {
            // 如果包含  则证明走到了入口点
            if(seen.contains(cur)) {
                return cur;
            }else {
                seen.add(cur);
            }

            cur = cur.next;
        }

        return null;
    }
}

2.双指针
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) break;
        }


        // 跳出循环有两种condition
        if(fast == null || fast.next == null) return null;


        // fast = head  两个指针一起走 直到相同
        fast = head;
        while(fast != slow) {
            fast = fast.next;
            slow = slow.next;
        }


        return slow;
    }
}
相关推荐
浅川.25几秒前
xtuoj 素数个数
数据结构·算法
少许极端1 小时前
算法奇妙屋(十五)-BFS解决边权为1的最短路径问题
数据结构·算法·bfs·宽度优先·队列·图解算法·边权为1的最短路径问题
ada7_1 小时前
LeetCode(python)——94.二叉
python·算法·leetcode·链表·职场和发展
不穿格子的程序员1 小时前
从零开始写算法——普通数组类题:数组操作中的“翻转技巧”与“前后缀分解”
数据结构·算法
curry____3031 小时前
study in PTA(高精度算法与预处理)(2025.12.3)
数据结构·c++·算法·高精度算法
代码游侠2 小时前
学习笔记——栈
开发语言·数据结构·笔记·学习·算法
Ayanami_Reii2 小时前
进阶数据结构应用-维护序列
数据结构·算法·线段树
CoderYanger2 小时前
C.滑动窗口-越长越合法/求最短/最小——2904. 最短且字典序最小的美丽子字符串
java·开发语言·数据结构·算法·leetcode·1024程序员节
别动哪条鱼2 小时前
FFmpeg API 数据结构及其详细说明:
数据结构·ffmpeg·音视频·aac
Ayanami_Reii3 小时前
进阶数据结构-线段树
数据结构·算法·线段树