题目形容
这是 LeetCode 上的 707. 设计链表 ,难度为 中等。
Tag : 「链表」
设计链表的实现。您能够抉择应用单链表或双链表。
单链表中的节点应该具备两个属性:val
和 next
。val
是以后节点的值,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多平台公布