LeetCode707:設計連結串列 Design Linked List
愛寫bug (ID:iCodeBugs)
設計連結串列的實現。您可以選擇使用單連結串列或雙連結串列。單連結串列中的節點應該具有兩個屬性:val
和 next
。val
是當前節點的值,next
是指向下一個節點的指標/引用。如果要使用雙向連結串列,則還需要一個屬性 prev
以指示連結串列中的上一個節點。假設連結串列中的所有節點都是 0-index 的。
在連結串列類中實現這些功能:
- get(index):獲取連結串列中第
index
個節點的值。如果索引無效,則返回-1
。 - addAtHead(val):在連結串列的第一個元素之前新增一個值為
val
的節點。插入後,新節點將成為連結串列的第一個節點。 - addAtTail(val):將值為
val
的節點追加到連結串列的最後一個元素。 - addAtIndex(index,val):在連結串列中的第
index
個節點之前新增值為val
的節點。如果index
等於連結串列的長度,則該節點將附加到連結串列的末尾。如果index
大於連結串列長度,則不會插入節點。 - deleteAtIndex(index):如果索引
index
有效,則刪除連結串列中的第index
個節點。
Design your implementation of the linked list. You can choose to use the singly linked list or the doubly linked list. A node in a singly linked list should have two attributes: val
and next
. val
is the value of the current node, and next
is a pointer/reference to the next node. If you want to use the doubly linked list, you will need one more attribute prev
to indicate the previous node in the linked list. Assume all nodes in the linked list are 0-indexed.
Implement these functions in your linked list class:
- get(index) : Get the value of the
index
-th node in the linked list. If the index is invalid, return-1
. - addAtHead(val) : Add a node of value
val
before the first element of the linked list. After the insertion, the new node will be the first node of the linked list. - addAtTail(val) : Append a node of value
val
to the last element of the linked list. - addAtIndex(index, val) : Add a node of value
val
before theindex
-th node in the linked list. Ifindex
equals to the length of linked list, the node will be appended to the end of linked list. If index is greater than the length, the node will not be inserted. - deleteAtIndex(index) : Delete the
index
-th node in the linked list, if the index is valid.
示例:
MyLinkedList linkedList = new MyLinkedList();
linkedList.addAtHead(1);
linkedList.addAtTail(3);
linkedList.addAtIndex(1,2); //連結串列變為1-> 2-> 3
linkedList.get(1); //返回2
linkedList.deleteAtIndex(1); //現在連結串列是1-> 3
linkedList.get(1); //返回3
提示:
- 所有值都在
[1, 1000]
之內。 - 操作次數將在
[1, 1000]
之內。 - 請不要使用內建的 LinkedList 庫。
解題思路:
先看圖解:
- 單連結串列新增操作
如果我們想在給定的結點 prev
之後新增新值,我們應該:
- 使用給定值初始化新結點
cur;
- 將
cur
的“next”欄位連結到 prev 的下一個結點next
; - 將
prev
中的“next”欄位連結到cur
。
- 刪除第一個結點
如果我們想刪除第一個結點,策略會有所不同。
正如之前所提到的,我們使用頭結點 head
來表示連結串列。我們的頭是下面示例中的黑色結點 23。
如果想要刪除第一個結點,我們可以簡單地將下一個結點分配給 head
。也就是說,刪除之後我們的頭將會是結點 6。
連結串列從頭結點開始,因此結點 23 不再在我們的連結串列中。
圖片來源於LeetCode中國官網
高階程式設計語言中一般都有內建連結串列,這道題就是讓復現連結串列,看到有很多是用ArrayList、List等資料結構解的,很搞笑,題目說不能使用 LinkedList 庫,但 LinkedList 是繼承的ArrayList、List,,直接用這兩個庫一點意義都沒有。其實理解一下連結串列原理就好,高階語言都封裝好了連結串列,如果專案真的到了需要改寫連結串列底層結構來最佳化效能的那一步,那時候在實踐中基本已經摸清了這些東西。
Java:
class Node {//定義Node
int val;
Node next;
Node(int val) {
this.val = val;
this.next = null;
}
}
class MyLinkedList {
Node head;//頭
Node tail;//尾
int size = 0;//連結串列長度
public MyLinkedList() {//初始化資料
head = new Node(0);//為了方便初始化一個本不存在的head,值為0
tail = head;//初始下尾也指向和頭同一個物件
size = 0;
}
public int get(int index) {
if (index >= size || index < 0) {//index不在查詢區間返回-1
return -1;
}
Node cur = head;
for (int i = 0; i <= index; i++) {//從head一個一個向下遍歷,到index
cur = cur.next;
}
return cur.val;//返回值
}
public void addAtHead(int val) {
Node temp = head.next;//temp物件是真實連結串列的第一個節點(因為head一直是初始化的 0 )
head.next = new Node(val);//構造的虛擬節點head的下一個節點指向新插入的節點
head.next.next = temp;//新插入節點指向原本第一個真實節點
size++;//計數
if (size == 1) {
tail = head.next;//如果只有一個節點此時尾節點也指向新加入的節點
}
}
public void addAtTail(int val) {//新增尾節點
tail.next = new Node(val);//把尾節點下一個物件指向新加入節點即可
tail = tail.next;//重新整理尾節點為新加入的節點
size++;
}
public void addAtIndex(int index, int val) {
if (index > size) {//插入值不在範圍直接返回。
return;
}
Node cur = head;//當前節點從頭節點開始
for (int i = 0; i < index; i++) {//遍歷到 插入位置的前一個節點 因為要求是插入到index的前面
cur = cur.next;
}
Node temp = cur.next;//暫存當前節點的下一個節點
cur.next = new Node(val);//把當前節點下一個物件指向新節點
if (index == size) {
tail = cur.next;//如果插入位置剛好是最後一個則把尾節點指向新加入節點
}
cur.next.next = temp;//新節點的下一個節點指向暫存節點位置
size++;
}
public void deleteAtIndex(int index) {
if (index >= size || index < 0) {
return;
}
Node cur = head;//從頭節點遍歷到index目標節點的前一個節點 因為要刪除目標節點
for (int i = 0; i < index; i++) {
cur = cur.next;
}
cur.next = cur.next.next;//目標節點前一個節點的下一個節點指向目標節點的下一個節點
size--;//重新整理節點數量
if (cur.next == null) {
tail = cur;
}
}
}
Python3:
class Node:
def __init__(self, val, _next=None):
self.next = _next
self.val = val
class MyLinkedList:
def __init__(self):
self.head = None
self.tail = None
self.size = 0
def get(self, index: int) -> int:
if index > self.size - 1 or index < 0:
return -1
node = self.head
for i in range(index):
node = node.next
return node.val
def addAtHead(self, val: int) -> None:
node = Node(val, self.head)
self.head = node
if self.size == 0:
self.tail = node
self.size = self.size + 1
def addAtTail(self, val: int) -> None:
node = Node(val)
if self.size == 0:
self.head = self.tail = node # 原連結串列為空時,新增新節點後,更新連結串列的頭指標和尾指標為新增節點。
else:
self.tail.next = node # 原連結串列不為空時,使原尾指標指向新節點,即可將新節點新增至原連結串列尾部
self.tail = node # 更新尾指標
self.size = self.size + 1 # 更新此時連結串列的長度
def addAtIndex(self, index: int, val: int) -> None:
node = Node(val)
if index > self.size:
return
if index <= 0:
return self.addAtHead(val) # index 小於等於0都預設為頭指標後新增節點
if index == self.size: # 如果index等於連結串列的長度新增尾指標後新增節點
return self.addAtTail(val)
prev = self.head # 第一個節點物件開始遍歷
for i in range(index - 1):
prev = prev.next
temp = prev.next
prev.next = node
node.next = temp
self.size = self.size + 1
def deleteAtIndex(self, index: int) -> None:
if index < 0 or index >= self.size:
return
prev = self.head
if index == 0:
self.head = self.head.next
self.size = self.size - 1
return
for i in range(index - 1):
prev = prev.next
if index == self.size - 1:
self.tail = prev
prev.next = prev.next.next
self.size = self.size - 1
來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/506/viewspace-2823291/,如需轉載,請註明出處,否則將追究法律責任。
相關文章
- Q17 LeetCode707 設計連結串列LeetCode
- 【C++ 資料結構:連結串列】二刷LeetCode707設計連結串列C++資料結構LeetCode
- 【小白學演算法】5.連結串列(linked list)、連結串列的新增演算法
- 【資料結構與演算法】——連結串列(Linked List)資料結構演算法
- 演算法與資料結構基礎 - 連結串列(Linked List)演算法資料結構
- 演算法與資料結構-連結串列((linked-list)-Java實現單向連結串列演算法資料結構Java
- 資料結構與演算法——連結串列 Linked List(單連結串列、雙向連結串列、單向環形連結串列-Josephu 問題)資料結構演算法
- [LeetCode Python 3] 876. Middle of the Linked List(連結串列的中間結點)LeetCodePython
- 既然已經有陣列了,為什麼還要連結串列?JS連結串列(Linked-list)詳解陣列JS
- [LeetCode] 1367. Linked List in Binary Tree 二叉樹中的連結串列LeetCode二叉樹
- LeetCode 之 JavaScript 解答第141題 —— 環形連結串列 I(Linked List Cycle I)LeetCodeJavaScript
- LeetCode 83.Remove Duplicates from Sorted List(從已排序連結串列中除去重複) Easy/Linked ListLeetCodeREM排序
- C++ STL list連結串列C++
- linux核心原始碼 -- list連結串列Linux原始碼
- 707_設計連結串列
- **203.移除連結串列元素****707.設計連結串列****206.反轉連結串列**
- 【程式碼隨想錄】二、連結串列:2、設計連結串列
- 單向連結串列介面設計
- 程式碼隨想錄第3天 | 連結串列 203.移除連結串列元素,707.設計連結串列,206.反轉連結串列
- JavaScript資料結構之連結串列--設計JavaScript資料結構
- 隨想錄day3:203.移除連結串列元素|707.設計連結串列 |206.反轉連結串列
- 程式碼隨想錄:設計連結串列
- 連結串列 - 單向連結串列
- 連結串列-迴圈連結串列
- 連結串列-雙向連結串列
- 設計單向迴圈連結串列的介面
- 雙向連結串列介面設計(C語言)C語言
- TODO-力扣-707. 設計連結串列力扣
- Rust 程式設計,用連結串列實現棧Rust程式設計
- 連結串列4: 迴圈連結串列
- 連結串列-雙向通用連結串列
- 連結串列-單連結串列實現
- LeetCode | 141 linked list cycleLeetCode
- 雙向迴圈連結串列的介面設計(初版
- 連結串列-雙向非通用連結串列
- 【LeetCode】->連結串列->通向連結串列自由之路LeetCode
- 連結串列入門與插入連結串列
- Leetcode_86_分割連結串列_連結串列LeetCode