LeetCode 热题 100 之 160. 相交链表 206. 反转链表 234. 回文链表 141. 环形链表 142. 环形链表 II

  1. 相交链表

  2. 反转链表

  3. 回文链表

  4. 环形链表

  5. 环形链表 II

160. 相交链表

复制代码
public class Solution {
    public ListNode getIntersectionNode(ListNode headA, ListNode headB) {
        if (headA == null || headB == null) return null;
        ListNode pA = headA, pB = headB;
        while (pA != pB) {
            pA = pA == null ? headB : pA.next;
            pB = pB == null ? headA : pB.next;
        }
        return pA;
    }
}
解题思路1:双指针

双指针法是最优解,时间复杂度 O(n+m),空间复杂度 O(1):

  1. 初始化两个指针 pApB,分别指向链表 headAheadB 的头节点。

  2. 同时遍历两个链表,pA 走到 headA 末尾时,重新指向 headBpB 走到 headB 末尾时,重新指向 headA

  3. pApB 相遇时,该节点即为相交的起始节点;若遍历到末尾仍未相遇,则两链表不相交,返回 null

原理 :两个指针走过的总路程相等(lenA + lenB),若存在相交节点,必然会在相交点相遇

代码解释

  • 边界处理 :若任一链表为空,直接返回 null

  • 指针遍历pApB 交替遍历两个链表,保证最终路程相等。

  • 相遇判断 :当 pA == pB 时,要么是相交节点,要么同时到达末尾(null),直接返回即可。

    复制代码
    public class Solution {
        public ListNode getIntersectionNode(ListNode headA, ListNode headB) {
            int lenA = 0, lenB = 0;
            ListNode pA = headA, pB = headB;
            // 计算长度
            while (pA != null) { lenA++; pA = pA.next; }
            while (pB != null) { lenB++; pB = pB.next; }
            // 长链表先走
            pA = headA; pB = headB;
            if (lenA > lenB) {
                for (int i = 0; i < lenA - lenB; i++) pA = pA.next;
            } else {
                for (int i = 0; i < lenB - lenA; i++) pB = pB.next;
            }
            // 同时遍历找相遇点
            while (pA != pB) {
                pA = pA.next;
                pB = pB.next;
            }
            return pA;
        }
    }
    解题思路2:长度差法

    先计算两个链表的长度,让长链表的指针先走长度差的步数,再同时遍历,相遇点即为相交节点

    206. 反转链表

    /**

    • Definition for singly-linked list.
    • public class ListNode {
    • 复制代码
      int val;
    • 复制代码
      ListNode next;
    • 复制代码
      ListNode() {}
    • 复制代码
      ListNode(int val) { this.val = val; }
    • 复制代码
      ListNode(int val, ListNode next) { this.val = val; this.next = next; }
    • }
      */
      class Solution {
      public ListNode reverseList(ListNode head) {
      ListNode prev = null;
      ListNode curr = head;
      while (curr != null) {
      ListNode next = curr.next; // 保存下一个节点
      curr.next = prev; // 翻转当前节点指向
      prev = curr; // prev 前进
      curr = next; // curr 前进
      }
      return prev;
      }
      }
解题思路1:迭代法

核心思路 :用三个指针逐个翻转节点的指向,从前往后遍历链表,将当前节点的 next 指向前一个节点。

  • 初始化 prev = null(前一个节点)、curr = head(当前节点)、next = null(临时保存下一个节点)

  • 遍历链表:

    • 保存 curr.nextnext,避免断链

    • curr.next 指向 prev,完成当前节点的翻转

    • prev 移动到 currcurr 移动到 next

  • 遍历结束后,prev 就是新链表的头节点

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

解题思路2:递归法

核心思路:递归到链表末尾,从后往前逐层翻转节点指向。

  • 递归终止条件:head == nullhead.next == null,直接返回 head

  • 递归调用 reverseList(head.next) 得到子链表的新头节点

  • head.next.next = head,让子链表的末尾节点指向当前节点

  • head.next = null,断开原指向,避免成环

234. 回文链表

复制代码
/**
 * Definition for singly-linked list.
 * public class ListNode {
 *     int val;
 *     ListNode next;
 *     ListNode() {}
 *     ListNode(int val) { this.val = val; }
 *     ListNode(int val, ListNode next) { this.val = val; this.next = next; }
 * }
 */
class Solution {
   public boolean isPalindrome(ListNode head) {
    if (head == null || head.next == null) return true;a
    
    // 1. 快慢指针找中点
    ListNode slow = head, fast = head;
    while (fast.next != null && fast.next.next != null) {
        slow = slow.next;
        fast = fast.next.next;
    }
    
    // 2. 反转后半链表
    ListNode prev = null, curr = slow.next;
    while (curr != null) {
        ListNode next = curr.next;
        curr.next = prev;
        prev = curr;
        curr = next;
    }
    
    // 3. 双指针比较
    ListNode left = head, right = prev;
    while (right != null) {
        if (left.val != right.val) return false;
        left = left.next;
        right = right.next;
    }
    return true;
}
}
解题思路1:双指针 + 反转后半链表
  1. 用快慢指针找到链表中点(快指针走 2 步,慢指针走 1 步,快指针到末尾时慢指针指向中点)。

  2. 反转链表的后半部分。

  3. 用双指针分别从链表头和反转后的后半部分头开始遍历,逐一比较节点值是否相等。

  4. 若所有节点值都相等,则为回文链表;否则不是。

    class Solution {
    public boolean isPalindrome(ListNode head) {
    List<Integer> list = new ArrayList<>();
    ListNode curr = head;
    while (curr != null) {
    list.add(curr.val);
    curr = curr.next;
    }
    int left = 0, right = list.size() - 1;
    while (left < right) {
    if (!list.get(left).equals(list.get(right))) return false;
    left++;
    right--;
    }
    return true;
    }
    }

解题思路2:转数组 + 双指针

遍历链表,将所有节点值存入数组。

用双指针分别从数组首尾向中间遍历,逐一比较元素是否相等。

141. 环形链表

复制代码
/**
 * Definition for singly-linked list.
 * class ListNode {
 *     int val;
 *     ListNode next;
 *     ListNode(int x) {
 *         val = x;
 *         next = null;
 *     }
 * }
 */
public class Solution {
   public boolean hasCycle(ListNode head) {
    if (head == null || head.next == null) return false;
    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:快慢指针法(Floyd 判圈算法)
  • 初始化两个指针 slow(慢指针,每次走 1 步)和 fast(快指针,每次走 2 步)。

  • 若链表无环:快指针会先到达链表末尾(fast == nullfast.next == null),直接返回 false

  • 若链表有环:快指针最终会和慢指针在环内相遇,此时返回 true

原理:快指针相对慢指针的速度为 1 步 / 次,若存在环,两者必然会在环中相遇。

复制代码
public class Solution {
  public boolean hasCycle(ListNode head) {
    Set<ListNode> visited = new HashSet<>();
    while (head != null) {
        if (visited.contains(head)) return true;
        visited.add(head);
        head = head.next;
    }
    return false;
}
}
解题思路2: 哈希表 法(超低效率)
  • 遍历链表,用哈希集合记录已访问的节点。

  • 若当前节点已在集合中,说明存在环;若遍历到末尾仍未重复,则无环。

142. 环形链表 II

复制代码
/**
 * Definition for singly-linked list.
 * class ListNode {
 *     int val;
 *     ListNode next;
 *     ListNode(int x) {
 *         val = x;
 *         next = null;
 *     }
 * }
 */
public class Solution {
  public ListNode detectCycle(ListNode head) {
    if (head == null || head.next == null) return null;
    ListNode slow = head, fast = head;
    // 1. 快慢指针找相遇点
    while (fast != null && fast.next != null) {
        slow = slow.next;
        fast = fast.next.next;
        if (slow == fast) break; // 找到相遇点
    }
    // 无环情况
    if (fast == null || fast.next == null) return null;
    // 2. slow 移回头部,同速遍历找入口
    slow = head;
    while (slow != fast) {
        slow = slow.next;
        fast = fast.next;
    }
    return slow;
}
}
解题思路1:快慢指针法(Floyd 判圈算法)
  1. 检测环并找到相遇点

    1. 用慢指针 slow(每次走 1 步)和快指针 fast(每次走 2 步)遍历链表。

    2. fastfast.nextnull,说明无环,返回 null

    3. slowfast 相遇,说明存在环。

  2. 找到环的入口

    1. 相遇后,将 slow 移回链表头节点,fast 留在相遇点。

    2. slowfast相同速度 (每次 1 步)继续遍历,两者再次相遇的节点即为环的入口

数学原理 :设链表头到环入口的距离为 a,环入口到相遇点的距离为 b,环的长度为 c

  • 相遇时,slow 走过的路程:a+b

  • fast 走过的路程:a+b+k⋅c(k 为绕环的圈数,k≥1)

  • 因为 fast 速度是 slow 的 2 倍,所以:2(a+b)=a+b+k⋅c,化简得 a=k⋅c−b。

  • 这意味着:从链表头到环入口的距离 = 从相遇点绕环 k圈后再走到环入口的距离 。因此,让 slow 从头部出发,fast 从相遇点出发,同速前进,必然在环入口相遇。

    public ListNode detectCycle(ListNode head) {
    Set<ListNode> visited = new HashSet<>();
    while (head != null) {
    if (visited.contains(head)) return head;
    visited.add(head);
    head = head.next;
    }
    return null;
    }

解题思路2: 哈希表 法(超低效率)

遍历链表,用哈希集合记录已访问的节点,第一个重复出现的节点即为环的入口。

核心题型与最优解法汇总

题目 核心解法 时间复杂度 空间复杂度 核心思想
160. 相交链表 双指针法(路程对等) O(n+m) O(1) 两指针分别遍历 A+B 和 B+A,路程相等则必在相交点相遇
206. 反转链表 迭代法(双指针) O(n) O(1) 逐个翻转节点指向,用 prev/curr/next 三个指针完成方向反转
234. 回文链表 快慢指针 + 反转后半链表 O(n) O(1) 找中点→反转后半段→双指针对比前后段,实现原地判断
141. 环形链表 快慢指针(Floyd 判圈) O(n) O(1) 快指针速度 2 倍于慢指针,有环则必相遇
142. 环形链表 II 快慢指针 + 入口定位 O(n) O(1) 相遇后慢指针回起点,双指针同速遍历,相遇点即为环入口
相关推荐
y = xⁿ1 小时前
【LeetCodehot100】T114:二叉树展开为链表 T105:从前序与中序遍历构造二叉树
java·算法·链表
灰色小旋风1 小时前
力扣20有效的括号(C++)
c++·算法·leetcode·职场和发展
CoovallyAIHub2 小时前
AAAI 2026 | 华中科大联合清华等提出Anomagic:跨模态提示零样本异常生成+万级AnomVerse数据集(附代码)
深度学习·算法·计算机视觉
npupengsir2 小时前
nano vllm代码详解
人工智能·算法·vllm
m0_569881472 小时前
C++中的组合模式高级应用
开发语言·c++·算法
m0_730115112 小时前
高性能计算负载均衡
开发语言·c++·算法
灰色小旋风2 小时前
力扣19删除链表的倒数第N个结点(C++)
c++·算法·leetcode·链表
孞㐑¥2 小时前
算法—记忆化搜索
开发语言·c++·经验分享·笔记·算法
二进制星轨2 小时前
leecode-70-颜色分类-算法题解
数据结构·算法·排序算法