链表进阶:链表笔试真题

本文是链表笔试真题的刷题笔记,涵盖移除元素、找中间节点、找倒数第 K 个节点、合并有序链表、链表分割、回文判断、相交判定、环形链表与入口点、反转链表共 10 道高频题。每道题都给出题目链接、解题思路、完整代码与易错点,适合面试前集中复习。


阅读建议

  • 先独立思考:每道题先看题目链接,自己尝试 10 分钟,再对照思路与代码。
  • 关注易错点:每道题末尾的「注意」是面试高频失分点,务必理解。
  • 动手验证:建议在本地 IDE 或 LeetCode 在线环境跑通每段代码,加深记忆。

复杂度速查表

题目 时间复杂度 空间复杂度 核心技巧
1. 移除链表元素 O(n) O(1) 双指针遍历
2. 链表的中间节点 O(n) O(1) 先求长度再走一半
3. 链表的K个节点 O(n) O(1) 长度减 K
4. 合并两个有序链表 O(n+m) O(1) 尾插法 + 哨兵节点
5. 链表分割 O(n) O(1) 双链表拆分再拼接
6. 链表的回文结构 O(n) O(1) 找中点 + 反转后半段
7. 判定链表相交 O(n+m) O(1) 长度对齐
8. 环形链表 O(n) O(1) 快慢指针
9. 求环的入口点 O(n) O(1) 快慢指针 + 数学推导
10. 反转单链表 O(n) O(1) 三指针迭代

链表进阶:链表笔试真题

  • 1.移除链表元素
  • 2.链表的中间节点
  • 3.链表的K个节点
  • [链表的K个节点 1,搞出链表的尺寸,然后减去K 2,通过循环找出节点 3,将其设置为头节点 注意:链表可能为null,K可能大于链表尺寸,或者为0](#链表的K个节点 1,搞出链表的尺寸,然后减去K 2,通过循环找出节点 3,将其设置为头节点 注意:链表可能为null,K可能大于链表尺寸,或者为0)
  • 4.合并两个有序链表
  • [合并两个有序链表 !在这里插入图片描述(https://i-blog.csdnimg.cn/direct/771b9945bf124ea68c4ad7378b3b50ba.png) 注意:最后要判断cur1或者cur2](#合并两个有序链表 注意:最后要判断cur1或者cur2)
  • [5.给定 x, 把一个链表整理成前半部分小于 x, 后半部分大于等于 x 的形式](#5.给定 x, 把一个链表整理成前半部分小于 x, 后半部分大于等于 x 的形式)
  • 6.链表的回文结构
  • [方法一: 1.首先将链表复制一份,注意傀儡节点; 2.将复制的链表逆置.再分别遍历进行比较;](#方法一: 1.首先将链表复制一份,注意傀儡节点; 2.将复制的链表逆置.再分别遍历进行比较;)
  • [方法二: 1.取中间节点,从内部截取后半段做为链表; 2.再逆置后半段的链表; 3.以后半端的链表为基准,与前面进行比较;](#方法二: 1.取中间节点,从内部截取后半段做为链表; 2.再逆置后半段的链表; 3.以后半端的链表为基准,与前面进行比较;)
  • 7.判定链表相交
  • [判定链表相交 1.首先要对齐,题目给定的链表长度是不一样的,需要设置两个节点用于对齐这两个链表; 2.判断如果A的大小比B大,对齐B,减小长度到B; 3.判断如果B的大小比A大,对齐A,减小长度到A; 4.然后分别遍历比较这两个链表,注意比较的是==相同节点==,注意不断同时更新两个链表;](#判定链表相交 1.首先要对齐,题目给定的链表长度是不一样的,需要设置两个节点用于对齐这两个链表; 2.判断如果A的大小比B大,对齐B,减小长度到B; 3.判断如果B的大小比A大,对齐A,减小长度到A; 4.然后分别遍历比较这两个链表,注意比较的是==相同节点==,注意不断同时更新两个链表;)
  • 8.环形链表
  • [环形链表 这题采用双指针法,快慢指针相等时,表示有环;](#环形链表 这题采用双指针法,快慢指针相等时,表示有环;)
  • 9.求环的入口点
  • [2.这和找出如环点,先创建节点指向head,在创建节点指向slow或fast; 注意:这里是数学原理,包括前面用双指针判断是否有环,感兴趣可以自己证明,这个结论就是得出的结果是它们相差是成倍数的,只要运行就会相遇(带环)](#2.这和找出如环点,先创建节点指向head,在创建节点指向slow或fast; 注意:这里是数学原理,包括前面用双指针判断是否有环,感兴趣可以自己证明,这个结论就是得出的结果是它们相差是成倍数的,只要运行就会相遇(带环))
  • 10.反转单链表

1.移除链表元素

移除链表元素

解析

这里要删除所有该整数的节点

首先我们需要找到被删除的节点以及它前一个节点,定义两个节点;

ListNode cur = head.next

ListNode pre = head

答案

java 复制代码
class Solution {
    public ListNode removeElements(ListNode head, int val) {
        if(head==null){
            return null;
        }
        ListNode cur = head.next;
        ListNode pre = head;
        while(cur!=null){
            if(cur.val==val){
                pre.next = cur.next;
                cur = cur.next;
            }
            else{
                pre = cur;
                cur = cur.next;
            }
        }
        if(head.val==val){
            head = head.next;
            return head;
        }
        return head;
    }
}

2.链表的中间节点

链表的中间节点

java 复制代码
    public ListNode middleNode(ListNode head) {
        int size = 0;
for(ListNode cur = head;cur!=null;cur = cur.next){
    size++;
}
        ListNode cur = head;
        for(int i = 0;i<size/2;i++){
            cur = cur.next;
        }
        head = cur;
        return head;
    }

3.链表的K个节点

链表的K个节点

1,搞出链表的尺寸,然后减去K
2,通过循环找出节点
3,将其设置为头节点
注意:链表可能为null,K可能大于链表尺寸,或者为0

java 复制代码
public class Solution {

    public ListNode FindKthToTail(ListNode head,int k) {

if(head==null){

    return head;

}

int size = 0;

for(ListNode cur = head;cur!=null;cur = cur.next){

    size++;

}

if(k==0){

    return null;

}

if(k>size){

    k= size/k;

}

k = size-k;

ListNode cur = head;

for(int i = 0;i<k;i++){

cur = cur.next;

}

head = cur;

return head;

    }

4.合并两个有序链表

合并两个有序链表


注意:最后要判断cur1或者cur2

java 复制代码
 public ListNode mergeTwoLists(ListNode list1, ListNode list2) {
        ListNode Dhead = new ListNode(0);
        ListNode Dtail = Dhead;
        ListNode cur1 = list1;
        ListNode cur2 = list2;
        while(cur1!=null&&cur2!=null){
if(cur1.val<cur2.val){
    Dtail.next = cur1;
    cur1 = cur1.next;
    Dtail = Dtail.next;
}
else{
    Dtail.next = cur2;
    cur2 = cur2.next;
    Dtail = Dtail.next;
}
        }
        if(cur1==null){
            Dtail.next = cur2;
        }
          if(cur2==null){
            Dtail.next = cur1;
        }
        return Dhead.next;
    }

5.给定 x, 把一个链表整理成前半部分小于 x, 后半部分大于等于 x 的形式

链表分割

java 复制代码
/*
    解题思路:
     1. 构造两个新链表lessHead和greatHead,为了后序尾插简单,将链表构造成带头结点的
     2. 遍历链表,将小于x的节点往lessHead尾部插入,较大的节点往greatHead尾部插入
     3. 将greatHead拼接在lessHead之后形成一个链表并返回
*/ 
public class Partition {
    public ListNode partition(ListNode pHead, int x) {
        if(pHead == null){
            return null;
        }
        
        // 1. 构造两个新链表---为了后序尾插简单,将链表构造成带头结点的
        ListNode lessHead = new ListNode(0);
        ListNode tailL = lessHead;
        
        ListNode greatHead = new ListNode(0);
        ListNode tailG = greatHead;
        // 遍历链表,将小于x的节点往lessHead尾部插入,较大的节点往greatHead尾部插入
        ListNode cur = pHead;
        while(cur != null){
            if(cur.val < x){
                tailL.next = cur;
                tailL = cur;
            }else{
                tailG.next = cur;
                tailG = cur;
            }
            
            cur = cur.next;
        }
        
        // 将greatHead拼接在lessHead之后形成一个链表
        tailL.next = greatHead.next;
        tailG.next = null;
        return lessHead.next;
    }
}

6.链表的回文结构

方法一:

1.首先将链表复制一份,注意傀儡节点;
2.将复制的链表逆置.再分别遍历进行比较;

java 复制代码
 public boolean chkPalindrome(ListNode A) {
        if (A == null) {
            return false;
        }
        if (A.next == null) {
            return true;
        }
        write code here
        ListNode head = new ListNode(0);
        ListNode tail = head;
        for (ListNode cur = A; cur != null; cur = cur.next) {
            tail.next = cur;
            tail = tail.next;
        }
        head = head.next;
        ListNode cur = head;
        ListNode pre = null;
        while (cur != null) {
            ListNode next = cur.next;
            cur.next = pre;
            pre = cur;
            cur = next;
        }
        head = pre;
        ListNode cur1 = A;
        ListNode cur2 = head;
        while (cur1 != null && cur2 != null) {
            if (cur1.val != cur2.val) {
                return false;
            }
            cur1 = cur1.next;
            cur2 = cur2.next;
        }
        return true;
        }

方法二:

1.取中间节点,从内部截取后半段做为链表;
2.再逆置后半段的链表;
3.以后半端的链表为基准,与前面进行比较;

java 复制代码
    public boolean chkPalindrome(ListNode A) {
        if (A == null) {
            return false;
        }
        if (A.next == null) {
            return true;
        }
        int size = 0;
        for (ListNode cur = A; cur != null; cur = cur.next) {
            size++;
        }
        ListNode cur = A;
        for (int i = 0; i < size / 2; i++) {
            cur = cur.next;
        }
        ListNode B = cur;
        ListNode start = cur;
        ListNode pre = null;
        while(start!=null){
            if(start.next==null){
                B = start;
            }
ListNode next = start.next;
start.next = pre;
pre = start;
start = next;
        }
        ListNode  cur1 = A;
        ListNode cur2 = B;
        while(cur2!=null&&cur2!=null){
            if(cur2.val!=cur1.val){
                return false;
            }
            cur1 = cur1.next;
            cur2 = cur2.next;
        }
        return true;
    }

7.判定链表相交

判定链表相交

1.首先要对齐,题目给定的链表长度是不一样的,需要设置两个节点用于对齐这两个链表;
2.判断如果A的大小比B大,对齐B,减小长度到B;
3.判断如果B的大小比A大,对齐A,减小长度到A;
4.然后分别遍历比较这两个链表,注意比较的是相同节点,注意不断同时更新两个链表;

java 复制代码
public class Solution {

    public int getSize(ListNode list) {

        int size = 0;



        for (ListNode cur = list; cur != null; cur = cur.next) {

            size++;

        }

        return size;

    }



    public ListNode getIntersectionNode(ListNode headA, ListNode headB) {

                ListNode curA = headA;

        ListNode curB = headB;

        if (headA == null || headB == null) {

            return null;

        }

        int sizeA = getSize(headA);

        int sizeB = getSize(headB);

        if (sizeA < sizeB) {

            int diff = sizeB - sizeA;

            for (int i = 0; i < diff; i++) {

               curB = curB.next;

            }

        } else {

            int diff = sizeA - sizeB;

            for (int i = 0; i < diff; i++) {

                curA = curA.next;

            }

        }

        while (curA != null && curB != null) {

            if (curA == curB) {

                return curB;

            }

            curA = curA.next;

            curB = curB.next;

        }

        return null;

    }

8.环形链表

环形链表

这题采用双指针法,快慢指针相等时,表示有环;

java 复制代码
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;

    }

9.求环的入口点

环形链表 II

1.先判断是否有环,这一步很重要,用双指针;

java 复制代码
      if (head == null || head.next == null) {
            return null;
        }
        ListNode slow = head;
        ListNode fast = head;
        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.这和找出如环点,先创建节点指向head,在创建节点指向slow或fast;

注意:这里是数学原理,包括前面用双指针判断是否有环,感兴趣可以自己证明,这个结论就是得出的结果是它们相差是成倍数的,只要运行就会相遇(带环)

类似于跑圈,校园里总会有身体不错的,他速度快,把人家套圈了

java 复制代码
ListNode cur1 = head;
        ListNode cur2 = fast;
        while (cur1 != cur2) {
            cur1 = cur1.next;
            cur2 = cur2.next;
        }
        return cur1;
    }

10.反转单链表

反转单链表

这个用的是三指针法;

图解:

这是三个指针

java 复制代码
 public ListNode reverseList(ListNode head) {
        if(head == null){
            return head;
        }
        if(head.next == null){
            return head;
        }
        ListNode pre = null;
        ListNode cur = head;
        while(cur!=null){
            ListNode next = cur.next;
            if(next == null){
                head = cur;
            }
            cur.next = pre;
            pre = cur;
            cur = next;
        }
        return head;
    }
相关推荐
LB21121 小时前
力扣102 198 70 55
数据结构·算法·leetcode
刘天远2 小时前
企业 Agent 需求怎么写:数据结构、流程图与 Python 校验
数据结构·人工智能·python·流程图
明月_清风15 小时前
从二叉树到 B+ 树:一文搞懂工程中「树」的演化之道
数据结构·算法·go
渡我白衣15 小时前
并查集:基础认识与模拟实现
android·java·javascript·数据结构·c++·算法·并查集
血小板要健康16 小时前
链表 阶段算法总结
java·数据结构·笔记·算法·leetcode·链表
wuyk55520 小时前
107.FreeRTOS 链表深度解析:从原理到面试满分答案
c语言·开发语言·数据结构·stm32·单片机·链表·面试
-dzk-20 小时前
【链表】LC 138.随机链表的复制
数据结构·链表
洋不写bug21 小时前
链表补充练习,双链表的模拟实现
java·数据结构·链表·双链表·底层实现
白狐_7981 天前
408 数据结构|外部排序:流程与 k 路归并
数据结构·算法