leetcode
leetcode 701 ~ 750
设计链表

设计链表

难度:

标签:

题目描述

代码结果

运行时间: 208 ms, 内存: 15.8 MB


/*
 * This is a solution for implementing a singly linked list using Java Streams.
 * Note that Java Streams are not typically used for this type of problem, but we'll use them where applicable.
 */
import java.util.stream.IntStream;
class MyLinkedList {
    private class Node {
        int val;
        Node next;
        Node(int val) {
            this.val = val;
        }
    }
    private Node head;
    private int size;
    public MyLinkedList() {
        head = null;
        size = 0;
    }
    public int get(int index) {
        if (index < 0 || index >= size) {
            return -1;
        }
        Node[] node = {head};
        IntStream.range(0, index).forEach(i -> node[0] = node[0].next);
        return node[0].val;
    }
    public void addAtHead(int val) {
        Node newNode = new Node(val);
        newNode.next = head;
        head = newNode;
        size++;
    }
    public void addAtTail(int val) {
        Node newNode = new Node(val);
        if (head == null) {
            head = newNode;
        } else {
            Node current = head;
            while (current.next != null) {
                current = current.next;
            }
            current.next = newNode;
        }
        size++;
    }
    public void addAtIndex(int index, int val) {
        if (index < 0 || index > size) {
            return;
        }
        if (index == 0) {
            addAtHead(val);
        } else {
            Node newNode = new Node(val);
            Node[] node = {head};
            IntStream.range(0, index - 1).forEach(i -> node[0] = node[0].next);
            newNode.next = node[0].next;
            node[0].next = newNode;
            size++;
        }
    }
    public void deleteAtIndex(int index) {
        if (index < 0 || index >= size) {
            return;
        }
        if (index == 0) {
            head = head.next;
        } else {
            Node[] node = {head};
            IntStream.range(0, index - 1).forEach(i -> node[0] = node[0].next);
            node[0].next = node[0].next.next;
        }
        size--;
    }
}

解释

方法:

此题解实现了一个基本的单链表结构。类 ListNode 定义了链表的节点,包含节点值和指向下一个节点的指针。MyLinkedList 类则提供了链表的各种操作。初始化时创建一个虚拟头节点(dummy node)来简化边界条件处理。增加、删除和获取节点时都是通过遍历到目标位置来完成相应的操作。addAtHead 和 addAtTail 是特殊情况的 addAtIndex,分别在头部和尾部插入节点。

时间复杂度:

O(n)

空间复杂度:

O(n)

代码细节讲解

🦆
在`MyLinkedList`类中,为什么选择使用虚拟头节点(dummy node)而不是直接使用实际的头节点?
使用虚拟头节点可以简化插入和删除操作的边界条件处理。当链表为空时,直接操作实际头节点会需要特别处理头节点的变化,例如,插入新节点时需要更新头节点,删除时可能导致头节点不存在。而使用虚拟头节点,无论链表是否为空,头节点的插入和删除操作都可以统一处理,不需要单独考虑头节点是否存在的问题,因此代码更简洁,且易于维护。
🦆
为什么`addAtIndex`方法在插入时需要检查`index`是否大于链表当前的长度,而不是等于或大于?
在`addAtIndex`方法中,如果`index`等于链表的当前长度,这表示插入的位置是在链表的末尾。这是一个有效的操作,因为它等同于`addAtTail`方法的功能。如果`index`大于链表的长度,则表示插入点在链表的范围之外,这种情况下插入操作无法进行,因为它不会与现有的任何节点相邻接。因此,只有当`index`大于链表长度时,插入操作才被视为无效,从而直接返回不执行插入。
🦆
在执行`deleteAtIndex`操作时,如何确保在删除节点后链表的所有其他节点依然保持正确的连接状态?
在`deleteAtIndex`方法中,通过首先找到要删除的节点的前一个节点(称为`pre`),然后将`pre`的`next`指针更新为`pre.next.next`,实现删除操作。这种操作直接跳过了要删除的节点,将其从链表中移除,并且保持了前一个节点和后一个节点的正确连接。这样,除了被删除的节点外,所有其他节点依然保持正确的连接状态,确保链表的结构完整性。
🦆
如何处理在`addAtIndex`和`deleteAtIndex`方法中的边界情况,例如插入到链表的开始和结束位置?
在`addAtIndex`方法中,如果`index`为0或小于0,将在链表的开始位置插入新节点,这等同于调用`addAtHead`方法。如果`index`等于链表的当前长度,新节点将添加到链表的末尾,这与`addAtTail`方法的效果相同。在`deleteAtIndex`方法中,如果`index`为0,将删除链表的第一个实际节点,这需要特别处理虚拟头节点的`next`指针。对于插入和删除操作,通过调整`index`的值和检查`index`的有效性,可以很好地处理这些边界情况,确保操作的正确性。

相关问题