[链表] - 代码随想录 707. 设计链表

链表 - 代码随想录 707. 设计链表

1. 题目要求

在链表类中需要实现以下功能:

  1. get(index) :获取链表中第 index 个节点的值(索引无效时返回 -1
  2. addAtHead(val) :在链表头部插入值为 val 的新节点
  3. addAtTail(val) :在链表尾部追加值为 val 的新节点
  4. addAtIndex(index, val)
    • 在指定索引 index 前插入新节点
    • index = 链表长度 时插入到末尾
    • index > 链表长度 时不插入
    • index < 0 时插入到头部
  5. deleteAtIndex(index):删除指定索引的节点(索引无效时不操作)

2. 实现代码

java 复制代码
/**
 * 单链表实现类
 * 核心技巧:使用虚拟头节点(dummy head)简化边界处理
 */
class MyLinkedList {
    // 虚拟头节点(不存储实际数据)
    private Node dummyHead;
    // 链表当前长度
    private int size;
    
    // 节点内部类
    private class Node {
        int val;
        Node next;
        
        Node(int val, Node next) {
            this.val = val;
            this.next = next;
        }
    }

    // 构造函数初始化空链表
    public MyLinkedList() {
        this.dummyHead = new Node(0, null); // 虚拟头节点
        this.size = 0;                      // 初始长度
    }
    
    /**
     * 获取节点值
     * @param index 目标索引(0-indexed)
     * @return 值或-1(索引无效时)
     */
    public int get(int index) {
        // 索引有效性检查
        if (index < 0 || index >= size) return -1;
        
        Node curr = dummyHead.next; // 从实际头节点开始
        // 遍历到目标节点
        for (int i = 0; i < index; i++) {
            curr = curr.next;
        }
        return curr.val;
    }
    
    /**
     * 头部插入
     * 时间复杂度:O(1)
     */
    public void addAtHead(int val) {
        // 新节点指向原头节点,虚拟头节点指向新节点
        dummyHead.next = new Node(val, dummyHead.next);
        size++;
    }
    
    /**
     * 尾部插入
     * 时间复杂度:O(n)
     */
    public void addAtTail(int val) {
        Node curr = dummyHead;
        // 遍历到最后一个节点
        while (curr.next != null) {
            curr = curr.next;
        }
        // 尾部插入新节点
        curr.next = new Node(val, null);
        size++;
    }
    
    /**
     * 指定位置插入
     * 处理三种特殊情况:
     * 1. index < 0 → 头部插入
     * 2. index = size → 尾部插入
     * 3. index > size → 不操作
     */
    public void addAtIndex(int index, int val) {
        // 处理负索引(插入头部)
        if (index < 0) {
            addAtHead(val);
            return;
        }
        // 超范围索引不操作
        if (index > size) return;
        
        Node curr = dummyHead;
        // 定位到插入位置的前驱节点
        for (int i = 0; i < index; i++) {
            curr = curr.next;
        }
        // 创建新节点并插入
        curr.next = new Node(val, curr.next);
        size++;
    }
    
    /**
     * 删除节点
     * 注意:需确保前驱节点.next不为空
     */
    public void deleteAtIndex(int index) {
        // 索引有效性检查
        if (index < 0 || index >= size) return;
        
        Node curr = dummyHead;
        // 定位到删除位置的前驱节点
        for (int i = 0; i < index; i++) {
            curr = curr.next;
        }
        // 跳过目标节点(自动GC回收)
        curr.next = curr.next.next;
        size--;
    }
}

/**
 * 使用示例:
 * MyLinkedList obj = new MyLinkedList();
 * int param_1 = obj.get(index);
 * obj.addAtHead(val);
 * obj.addAtTail(val);
 * obj.addAtIndex(index,val);
 * obj.deleteAtIndex(index);
 */

3. 关键实现细节

  1. 虚拟头节点(dummy head)

    • 始终位于链表头部之前,确保空链表操作统一
    • 消除头节点操作的特殊逻辑分支
    • 插入/删除操作无需单独处理头节点情况
  2. 时间复杂度控制

    操作 时间复杂度 说明
    addAtHead O(1) 直接操作虚拟头节点
    get O(n) 需遍历到指定位置
    addAtTail O(n) 需遍历到链表末尾
    addAtIndex O(n) 需遍历到目标位置前驱节点
    deleteAtIndex O(n) 需遍历到目标位置前驱节点
  3. 边界处理强化

    • 所有操作前进行索引有效性验证
    • addAtIndex 明确处理负索引和超范围索引
    • deleteAtIndex 确保不操作无效索引
  4. 结构设计要点

    • 内部 Node 类封装节点数据与指针
    • size 计数器实时维护链表长度
    • 所有操作后同步更新 size
相关推荐
Kx_Triumphs7 小时前
HDU4348 To the moon(主席树区间修改模板)
算法·题解
旖-旎7 小时前
《LeetCode647 回文子串 || LeetCode 5 最长回文子串》
c++·算法·leetcode·动态规划·哈希算法
轻颂呀8 小时前
约瑟夫环问题
算法
凤凰院凶涛QAQ9 小时前
《Java版数据结构 & 集合类剖析》栈与队列:“push/pop 是栈的灵魂,offer/poll 是队列的骨架——四组 API,两种人生”
java·开发语言·数据结构
科技大视界10 小时前
投资AI项目,传统尽调不够用了——李章虎律师拆解算法、数据、算力三大雷区
人工智能·算法·数据挖掘
郝学胜-神的一滴10 小时前
算法实战:最小k个数——大顶堆的优雅解法
开发语言·数据结构·c++·python·程序人生·算法·排序算法
Irissgwe10 小时前
算法滑动窗口
数据结构·算法
怪兽学LLM10 小时前
LeetCode 105. 从前序与中序遍历序列构造二叉树:分治递归思路详解
算法·leetcode·职场和发展
可编程芯片开发11 小时前
基于PI控制的三相整流器控制系统的simulink建模与仿真,包含超级电容充电和电机
算法