题目形容

这是 LeetCode 上的 707. 设计链表 ,难度为 中等

Tag : 「链表」

设计链表的实现。您能够抉择应用单链表或双链表。

单链表中的节点应该具备两个属性:val 和 nextval 是以后节点的值,next 是指向下一个节点的指针/援用。

如果要应用双向链表,则还须要一个属性 prev 以批示链表中的上一个节点。假如链表中的所有节点都是 0-index 的。

在链表类中实现这些性能:

  • get(index):获取链表中第 index 个节点的值。如果索引有效,则返回-1
  • addAtHead(val):在链表的第一个元素之前增加一个值为 val 的节点。插入后,新节点将成为链表的第一个节点。
  • addAtTail(val):将值为 val 的节点追加到链表的最初一个元素。
  • addAtIndex(index,val):在链表中的第 index 个节点之前增加值为 val  的节点。如果 index 等于链表的长度,则该节点将附加到链表的开端。如果 index 大于链表长度,则不会插入节点。如果 index 小于 0,则在头部插入节点。
  • deleteAtIndex(index):如果索引 index 无效,则删除链表中的第 index 个节点。

示例:

MyLinkedList linkedList = new MyLinkedList();linkedList.addAtHead(1);linkedList.addAtTail(3);linkedList.addAtIndex(1,2);   //链表变为1-> 2-> 3linkedList.get(1);            //返回2linkedList.deleteAtIndex(1);  //当初链表是1-> 3linkedList.get(1);            //返回3

提醒:

  • 所有 val 值都在 $[1, 1000]$ 之内。
  • 操作次数将在  $[1, 1000]$ 之内。
  • 请不要应用内置的 LinkedList 库。

双向链表

一道手写链表裸题(啊嘿,$9$ 月流动的同学示意很棒

因为须要波及局部 index 相干操作,因而咱们能够实现一个「双向链表」,同时应用变量 sz 记录下以后链表的总长度,这样在波及 index 操作时,可从较近的一边登程遍历,剩下的则是惯例的链表节点操作。

一些细节:所有的链表题目咱们都能够引入前后哨兵来简化边界解决;同时能写双链表天然能写单链表,因而如果你没有顺利写出双链表的话,在看了题解写完双链表后,再手写一遍单链表作为练习。

Java 代码:

class MyLinkedList {    class Node {        Node prev, next;        int val;        Node (int _val) {            val = _val;        }    }    Node he = new Node(-1), ta = new Node(-1);    int sz = 0;    public MyLinkedList() {        he.next = ta; ta.prev = he;    }    public int get(int index) {        Node node = getNode(index);        return node == null ? -1 : node.val;    }    public void addAtHead(int val) {        Node node = new Node(val);                node.next = he.next; node.prev = he;        he.next.prev = node; he.next = node;        sz++;    }    public void addAtTail(int val) {        Node node = new Node(val);        node.prev = ta.prev; node.next = ta;        ta.prev.next = node; ta.prev = node;        sz++;    }    public void addAtIndex(int index, int val) {        if (index > sz) return ;        if (index <= 0) {            addAtHead(val);         } else if (index == sz) {            addAtTail(val);        } else {            Node node = new Node(val), cur = getNode(index);            node.next = cur; node.prev = cur.prev;            cur.prev.next = node; cur.prev = node;            sz++;        }    }    public void deleteAtIndex(int index) {        Node cur = getNode(index);        if (cur == null) return ;        cur.next.prev = cur.prev;        cur.prev.next = cur.next;        sz--;    }    Node getNode(int index) {        boolean isLeft = index < sz / 2;        if (!isLeft) index = sz - index - 1;        for (Node cur = isLeft ? he.next : ta.prev; cur != ta && cur != he; cur = isLeft ? cur.next : cur.prev) {            if (index-- == 0) return cur;        }        return null;    }}

TypeScript 代码:

class TNode {    prev: TNode    next: TNode    val: number    constructor(_val: number) {        this.val = _val    }}class MyLinkedList {    he = new TNode(-1)    ta = new TNode(-1)    sz = 0    constructor() {        this.he.next = this.ta; this.ta.prev = this.he        }    get(index: number): number {        const node = this.getNode(index)        return node == null ? -1 : node.val    }    addAtHead(val: number): void {        const node = new TNode(val)        node.next = this.he.next; node.prev = this.he        this.he.next.prev = node; this.he.next = node        this.sz++    }    addAtTail(val: number): void {        const node = new TNode(val)        node.prev = this.ta.prev; node.next = this.ta        this.ta.prev.next = node; this.ta.prev = node        this.sz++    }    addAtIndex(index: number, val: number): void {        if (index > this.sz) return         if (index <= 0) {            this.addAtHead(val)        } else if (index == this.sz) {            this.addAtTail(val)        } else {            const node = new TNode(val), cur = this.getNode(index)            node.next = cur; node.prev = cur.prev            cur.prev.next = node; cur.prev = node            this.sz++        }    }    deleteAtIndex(index: number): void {        const cur = this.getNode(index)        if (cur == null) return         cur.prev.next = cur.next        cur.next.prev = cur.prev        this.sz--    }    getNode(index: number): TNode | null {        const isLeft = index < this.sz / 2        if (!isLeft) index = this.sz - index - 1        for (let cur = isLeft ? this.he.next : this.ta.prev; cur != this.ta && cur != this.he; cur = isLeft ? cur.next : cur.prev) {            if (index-- == 0) return cur        }        return null    }}

Python 代码:

class Node:    def __init__(self, _val):        self.val = _val        self.prev = None        self.next = Noneclass MyLinkedList:    def __init__(self):        self.he = Node(-1)        self.ta = Node(-1)        self.he.next = self.ta        self.ta.prev = self.he        self.sz = 0    def get(self, index: int) -> int:        node = self.getNode(index)        return node.val if node else -1    def addAtHead(self, val: int) -> None:        node = Node(val)        node.next = self.he.next        node.prev = self.he        self.he.next.prev = node        self.he.next = node        self.sz += 1    def addAtTail(self, val: int) -> None:        node = Node(val)        node.prev = self.ta.prev        node.next = self.ta        self.ta.prev.next = node        self.ta.prev = node        self.sz += 1    def addAtIndex(self, index: int, val: int) -> None:        if index > self.sz:            return         if index <= 0:            self.addAtHead(val)        elif index == self.sz:            self.addAtTail(val)        else:            node, cur = Node(val), self.getNode(index)            node.next = cur            node.prev = cur.prev            cur.prev.next = node            cur.prev = node            self.sz += 1    def deleteAtIndex(self, index: int) -> None:        node = self.getNode(index)        if node:            node.prev.next = node.next            node.next.prev = node.prev            self.sz -= 1    def getNode(self, index: int) -> Node | None:        isLeft = index < self.sz / 2        if not isLeft:            index = self.sz - index - 1        cur = self.he.next if isLeft else self.ta.prev        while cur != self.he and cur != self.ta:            if index == 0:                return cur            index -= 1            cur = cur.next if isLeft else cur.prev        return None
  • 工夫复杂度:波及 index 的相干操作复杂度为 $O(index)$;其余操作均为 $O(1)$
  • 空间复杂度:$O(n)$

最初

这是咱们「刷穿 LeetCode」系列文章的第 No.707 篇,系列开始于 2021/01/01,截止于起始日 LeetCode 上共有 1916 道题目,局部是有锁题,咱们将先把所有不带锁的题目刷完。

在这个系列文章外面,除了解说解题思路以外,还会尽可能给出最为简洁的代码。如果波及通解还会相应的代码模板。

为了不便各位同学可能电脑上进行调试和提交代码,我建设了相干的仓库:https://github.com/SharingSou... 。

在仓库地址里,你能够看到系列文章的题解链接、系列文章的相应代码、LeetCode 原题链接和其余优选题解。

更多更全更热门的「口试/面试」相干材料可拜访排版精美的 合集新基地

本文由mdnice多平台公布