链表高频 6 题精讲 | 从入门到熟练掌握链表操作

本系列可作为JAVA学习系列的笔记,文中提到的一些练习的代码,小编会将代码复制下来,大家复制下来就可以练习了,方便大家学习。

点赞关注不迷路!您的点赞、关注和收藏是对小编最大的支持和鼓励!

系列文章目录

JAVA初阶---------已更完

JAVA数据结构 DAY1-集合和时空复杂度

JAVA数据结构 DAY2-包装类和泛型

JAVA数据结构 DAY3-List接口

JAVA数据结构 DAY4-ArrayList

JAVA数据结构 DAY5-LinkedList

JAVA数据结构 DAY6-栈和队列


拓展目录

手把手教你用 ArrayList 实现杨辉三角:从逻辑推导到每行代码详解

链表高频 6 题精讲 | 从入门到熟练掌握链表操作


目录

目录

系列文章目录

拓展目录

目录

前言

[1. 删除链表中等于给定值 val 的所有节点](#1. 删除链表中等于给定值 val 的所有节点)

思路拆解

完整代码

复杂度分析

[2. 反转一个单链表](#2. 反转一个单链表)

思路拆解

完整代码

复杂度分析

[3. 返回链表的中间结点(偶数时返回第二个)](#3. 返回链表的中间结点(偶数时返回第二个))

思路拆解

完整代码运行

复杂度分析

[4. 输出链表中倒数第 k 个结点](#4. 输出链表中倒数第 k 个结点)

思路拆解

完整代码

复杂度分析

[5. 合并两个有序链表](#5. 合并两个有序链表)

思路拆解

完整代码

复杂度分析

[6. 以给定值 x 为基准分割链表](#6. 以给定值 x 为基准分割链表)

思路拆解

完整代码

复杂度分析

总结

总结


前言

小编作为新晋码农一枚,会定期整理一些写的比较好的代码,作为自己的学习笔记,会试着做一下批注和补充,如转载或者参考他人文献会标明出处,非商用,如有侵权会删改!欢迎大家斧正和讨论!

链表是数据结构中的基础且高频考点,本文通过 6 道经典题目,带你系统掌握链表的核心操作技巧,包括删除、反转、快慢指针、合并与分割。每道题都配有完整思路拆解、代码实现和复杂度分析,适合刚学链表的同学巩固基础,也适合面试前快速复习。


1. 删除链表中等于给定值 val 的所有节点

题目描述 :删除链表中所有值为 val 的节点,返回处理后的头节点。

思路拆解

  • 痛点分析:如果直接操作原链表,当头节点就是要删除的节点时,需要单独处理,逻辑会变得复杂。
  • 核心技巧:使用 ** 哨兵节点(哑节点)** 作为虚拟头节点,统一处理所有节点的删除逻辑,无需单独判断头节点。
  • 步骤
    1. 创建一个哨兵节点,让它的 next 指向原链表的头节点。
    2. 用一个 prev 指针从哨兵节点开始遍历。
    3. 如果 prev.next 的值等于 val,就跳过这个节点(prev.next = prev.next.next);否则,prev 指针后移。
    4. 最终返回哨兵节点的 next,也就是新链表的头节点。

完整代码

java 复制代码
public ListNode removeElements(ListNode head, int val) {
    // 创建哨兵节点
    ListNode dummy = new ListNode(-1);
    dummy.next = head;
    ListNode prev = dummy;
    
    while (prev.next != null) {
        if (prev.next.val == val) {
            // 删除目标节点
            prev.next = prev.next.next;
        } else {
            prev = prev.next;
        }
    }
    // 返回新链表的头节点
    return dummy.next;
}

复杂度分析

  • 时间复杂度:O (n),需要遍历一次链表。
  • 空间复杂度:O (1),仅使用常量额外空间。

2. 反转一个单链表

题目描述:反转链表,返回新的头节点。

思路拆解

  • 核心技巧迭代法 ,用三个指针(prevcurnext)逐步改变节点的指向。
  • 步骤
    1. 初始化 prevnullcur 指向原链表头节点。
    2. 遍历链表,每次保存当前节点的下一个节点到 next
    3. 将当前节点的 next 指向 prev,完成一次局部反转。
    4. 移动 prevcur 指针,继续处理下一个节点。
    5. 遍历结束后,prev 就是新链表的头节点。

完整代码

java 复制代码
public ListNode reverseList(ListNode head) {
    ListNode prev = null;
    ListNode cur = head;
    
    while (cur != null) {
        // 保存下一个节点
        ListNode next = cur.next;
        // 反转当前节点的指向
        cur.next = prev;
        // 指针后移
        prev = cur;
        cur = next;
    }
    return prev;
}

复杂度分析

  • 时间复杂度:O (n),遍历一次链表。
  • 空间复杂度:O (1),仅使用常量额外空间。

3. 返回链表的中间结点(偶数时返回第二个)

题目描述:返回链表的中间节点,如果有两个中间节点,则返回第二个。

思路拆解

  • 核心技巧快慢指针法。快指针每次走两步,慢指针每次走一步,当快指针走到链表末尾时,慢指针恰好指向中间节点。
  • 步骤
    1. 初始化快慢指针都指向头节点。
    2. 循环条件:fast != null && fast.next != null(保证快指针能走两步,避免空指针异常)。
    3. 快指针每次走两步,慢指针每次走一步。
    4. 循环结束后,慢指针就是中间节点。

完整代码运行

java 复制代码
public ListNode middleNode(ListNode head) {
    ListNode fast = head;
    ListNode slow = head;
    
    while (fast != null && fast.next != null) {
        fast = fast.next.next;
        slow = slow.next;
    }
    return slow;
}

复杂度分析

  • 时间复杂度:O (n),遍历一次链表。
  • 空间复杂度:O (1),仅使用常量额外空间。

4. 输出链表中倒数第 k 个结点

题目描述:输入一个链表,输出该链表中倒数第 k 个节点。

思路拆解

  • 核心技巧快慢指针法 。让快指针先走 k 步,然后快慢指针一起走,当快指针走到链表末尾时,慢指针恰好指向倒数第 k 个节点。
  • 步骤
    1. 初始化快慢指针都指向头节点。
    2. 快指针先走 k 步。
    3. 快慢指针一起走,直到快指针走到链表末尾。
    4. 此时慢指针指向的就是倒数第 k 个节点。

完整代码

java 复制代码
public ListNode getKthFromEnd(ListNode head, int k) {
    ListNode fast = head;
    ListNode slow = head;
    
    // 快指针先走k步
    for (int i = 0; i < k; i++) {
        fast = fast.next;
    }
    
    // 快慢指针一起走
    while (fast != null) {
        fast = fast.next;
        slow = slow.next;
    }
    return slow;
}

复杂度分析

  • 时间复杂度:O (n),遍历一次链表。
  • 空间复杂度:O (1),仅使用常量额外空间。

5. 合并两个有序链表

题目描述:将两个升序链表合并为一个新的升序链表并返回。

思路拆解

  • 核心技巧:使用 ** 哨兵节点(哑节点)** 作为结果链表的起点,简化头节点的处理。
  • 步骤
    1. 创建一个哨兵节点,用 cur 指针指向它,作为结果链表的尾部指针。
    2. 遍历两个链表,每次选择值较小的节点接到 cur 的后面。
    3. 移动对应链表的指针和结果链表的尾部指针。
    4. 当其中一个链表遍历完,将另一个链表的剩余部分直接接到结果链表的尾部。
    5. 返回哨兵节点的 next,也就是合并后链表的头节点。

完整代码

java 复制代码
public ListNode mergeTwoLists(ListNode list1, ListNode list2) {
    ListNode dummy = new ListNode(-1);
    ListNode cur = dummy;
    
    while (list1 != null && list2 != null) {
        if (list1.val < list2.val) {
            cur.next = list1;
            list1 = list1.next;
        } else {
            cur.next = list2;
            list2 = list2.next;
        }
        cur = cur.next;
    }
    
    // 处理剩余节点
    cur.next = list1 != null ? list1 : list2;
    return dummy.next;
}

复杂度分析

  • 时间复杂度:O (n + m),n 和 m 分别为两个链表的长度。
  • 空间复杂度:O (1),仅使用常量额外空间。

6. 以给定值 x 为基准分割链表

题目描述:将链表分割为两部分,所有小于 x 的节点排在大于或等于 x 的节点之前。

思路拆解

  • 核心技巧:把链表拆分成两个子链表,再进行拼接。
  • 步骤
    1. 定义四个指针:lessHead/lessTail 存储小于 x 的节点,moreHead/moreTail 存储大于等于 x 的节点。
    2. 遍历原链表,将每个节点根据值的大小加入对应的子链表。
    3. 遍历每个节点时,先保存它的下一个节点,然后断开它与原链表的连接(避免成环)。
    4. 拼接两个子链表:如果小于 x 的链表为空,直接返回大于等于 x 的链表;否则,将大于等于 x 的链表拼接到小于 x 的链表的尾部。
    5. 返回拼接后链表的头节点。

完整代码

java 复制代码
public ListNode partition(ListNode pHead, int x) {
    ListNode lessHead = null, lessTail = null;
    ListNode moreHead = null, moreTail = null;
    ListNode cur = pHead;
    
    while (cur != null) {
        ListNode next = cur.next;
        cur.next = null; // 断开原连接,避免成环
        
        if (cur.val < x) {
            if (lessHead == null) {
                lessHead = lessTail = cur;
            } else {
                lessTail.next = cur;
                lessTail = lessTail.next;
            }
        } else {
            if (moreHead == null) {
                moreHead = moreTail = cur;
            } else {
                moreTail.next = cur;
                moreTail = moreTail.next;
            }
        }
        cur = next;
    }
    
    // 拼接两个链表
    if (lessHead == null) {
        return moreHead;
    }
    lessTail.next = moreHead;
    return lessHead;
}

复杂度分析

  • 时间复杂度:O (n),遍历一次链表。
  • 空间复杂度:O (1),仅使用常量额外空间。

总结

这 6 道题覆盖了链表的核心操作技巧,包括:

  • 哨兵节点:用于统一处理头节点的边界情况(如删除、合并)。
  • 快慢指针:用于找中间节点、倒数第 k 个节点等问题。
  • 迭代反转:通过指针改变节点指向实现链表反转。
  • 拆分 + 拼接:用于链表分割问题。

掌握这些技巧后,你可以应对绝大多数链表相关的面试题。


总结

以上就是今天要讲的内容,本文简单记录了java数据结构,仅作为一份简单的笔记使用,大家根据注释理解,您的点赞关注收藏就是对小编最大的鼓励!

相关推荐
lpfasd1238 小时前
物联网后端岗位java面试题
java·物联网·php
毕设源码李师姐8 小时前
计算机毕设 java 基于 java 的图书馆借阅系统 智能图书馆借阅综合管理平台 基于 Java 的图书借阅与信息管理系统
java·开发语言·课程设计
忆~遂愿8 小时前
Runtime 上下文管理:计算实例的生命周期、延迟最小化与上下文切换优化
java·大数据·开发语言·人工智能·docker
powerfulhell9 小时前
寒假python作业5
java·前端·python
1尢晞19 小时前
Java学习
java·开发语言
阿杰真不会敲代码9 小时前
Mybatis-plus入门到精通
java·tomcat·mybatis
木井巳9 小时前
【递归算法】二叉搜索树中第K小的元素
java·算法·leetcode·深度优先·剪枝
铉铉这波能秀9 小时前
LeetCode Hot100 中 enumerate 函数的妙用(2026.2月版)
数据结构·python·算法·leetcode·职场和发展·开发
qq_297574679 小时前
【实战】POI 实现 Excel 多级表头导出(含合并单元格完整方案)
java·spring boot·后端·excel