[链表] - 代码随想录 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
相关推荐
罗湖老棍子10 分钟前
【区间DP】括号序列:如何求解最长合法子序列?(POJ 2955)
算法·动态规划·区间dp·区间动态规划·端点匹配型
王德博客14 分钟前
【实现常见排序算法】直接插入排序的算法思想
数据结构·算法·排序算法
m0_5648768415 分钟前
分布式训练DP与DDP
人工智能·深度学习·算法
纤纡.16 分钟前
逻辑回归实战进阶:交叉验证与采样技术破解数据痛点(一)
算法·机器学习·逻辑回归
重生之后端学习19 分钟前
146. LRU 缓存
java·数据结构·算法·leetcode·职场和发展
程曦曦21 分钟前
原地删除有序数组重复项:双指针法的艺术与实现
数据结构·算法·leetcode
你怎么知道我是队长22 分钟前
C语言---排序算法6---递归归并排序法
c语言·算法·排序算法
智驱力人工智能34 分钟前
景区节假日车流实时预警平台 从拥堵治理到体验升级的工程实践 车流量检测 城市路口车流量信号优化方案 学校周边车流量安全分析方案
人工智能·opencv·算法·安全·yolo·边缘计算
MicroTech202536 分钟前
微算法科技(NASDAQ :MLGO)抗量子攻击区块链共识机制:通过量子纠缠态优化节点验证流程,降低计算复杂度
科技·算法·区块链
pp起床37 分钟前
贪心算法 | part01
算法·贪心算法