1. 程式人生 > 其它 >707.設計連結串列

707.設計連結串列

707.設計連結串列

題目連結:707. 設計連結串列(中等)

題目描述

設計連結串列的實現。您可以選擇使用單鏈表或雙鏈表。單鏈表中的節點應該具有兩個屬性: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-> 3
linkedList.get(1); //返回2
linkedList.deleteAtIndex(1); //現在連結串列是1-> 3
linkedList.get(1); //返回3

提示:

所有val值都在 [1, 1000] 之內。
操作次數將在 [1, 1000] 之內。
請不要使用內建的 LinkedList 庫。

題解

思路:這道題需要掌握連結串列的基本操作。新增”虛擬頭節點“能讓首元節點的操作同非首元節點的操作一致。

程式碼(C++版本):

1、單鏈表

#include "iostream"
using namespace std;

//單鏈表
class MyLinkedList {
public:
    struct LinkedNode {
        int val;
        LinkedNode *next;
        LinkedNode(int
val) : val(val), next(NULL) {} }; private: LinkedNode* headNode; int size; public: //初始化連結串列 //如果連結串列帶有一個虛擬頭節點,那麼首元節點的操作也跟其他節點的操作一致,否則要單獨考慮對首元節點的操作 MyLinkedList() { headNode = new LinkedNode(0);//頭節點為虛擬節點 size = 0; } //獲取連結串列中第 index 個節點的值。如果索引無效,則返回-1。 //不包括頭節點,首元節點的索引為0 int get(int index) { if (index < 0 || index > size - 1) { return -1; } int i = 0;//用於計數 LinkedNode* tp = headNode; while (tp->next != NULL) { if (i == index) { return tp->next->val; } else { i++; tp = tp->next; } } return -1; } //在連結串列的第一個元素之前新增一個值為 val 的節點。插入後,新節點將成為連結串列的第一個節點。 //頭節點除外,第一個元素是首元節點 void addAtHead(int val) { LinkedNode* node = new LinkedNode(val); node->next = headNode->next; headNode->next = node; size += 1; } // 錯誤寫法,這樣會改變頭指標所指的內容(在類中定義的函式,相對於對頭節點加了&) // //將值為 val 的節點追加到連結串列的最後一個元素。 // void addAtTail(int val) { // LinkedNode* node = new LinkedNode(val); // while (headNode->next != NULL) { // headNode = headNode->next; // } // headNode->next = node; // size += 1; // } //將值為 val 的節點追加到連結串列的最後一個元素。 void addAtTail(int val) { LinkedNode* node = new LinkedNode(val); LinkedNode* tp = headNode; while (tp->next != NULL) { tp = tp->next; } tp->next = node; size += 1; } // 在連結串列中的第index個節點之前新增值為val的節點。 // 如果index等於連結串列的長度,則該節點將附加到連結串列的末尾。 // 如果 index 大於連結串列長度,則不會插入節點。 // 如果index小於0,則在頭部插入節點。 void addAtIndex(int index, int val) { if (index == size ) { addAtTail(val); } else if (index > size) { return; } else if (index < 0) { addAtHead(val); } else { LinkedNode* node = new LinkedNode(val); LinkedNode* tp = headNode; for (int i = 0; i < index; i++) { tp = tp->next; } node->next = tp->next; tp->next = node; size += 1; } } //deleteAtIndex(index):如果索引 index 有效,則刪除連結串列中的第 index 個節點。 void deleteAtIndex(int index) { if (index >= 0 && index < size) { LinkedNode* tp = headNode; for (int i = 0; i < index; i++) { tp = tp->next; } LinkedNode* dp = tp->next; tp->next = tp->next->next; delete dp; size -= 1; } } //列印連結串列 void printLinkedList() { LinkedNode* tp = headNode; while (tp->next != NULL) { cout << tp->next->val << " "; tp = tp->next; } cout << endl; } }; int main() { MyLinkedList* linkedList = new MyLinkedList(); linkedList->addAtHead(1); linkedList->printLinkedList(); linkedList->addAtTail(3); linkedList->printLinkedList(); linkedList->addAtIndex(1, 2); //連結串列變為1-> 2-> 3 linkedList->printLinkedList(); int r1 = linkedList->get(1); //返回2 cout << r1 << endl; linkedList->deleteAtIndex(1); //現在連結串列是1-> 3 linkedList->printLinkedList(); int r2 = linkedList->get(1); //返回3 cout << r2 << endl; return 0; }

分析

  • 時間複雜度: addAtHead: O(1) addAtInder,get,deleteAtIndex: O(k),其中 k 指的是元素的索引。 addAtTail:O(N),其中 N 指的是連結串列的元素個數。

  • 空間複雜度:所有的操作都是 O(1)。