203.移除連結串列元素
題目連結:https://leetcode.cn/problems/remove-linked-list-elements/
題目難度:簡單
文章講解:https://programmercarl.com/0203.移除連結串列元素.html
影片講解: https://www.bilibili.com/video/BV18B4y1s7R9
題目狀態:透過
個人思路:
從連結串列頭部開始依次往下遍歷,當遇到和val
值相等的元素就將其移除(walk->next = walk->next->next
),最後返回修改後的連結串列。
遇到的問題:
- 直接將遍歷指標
walk
初始化在了連結串列頭,沒能考慮到頭節點就是需要移除的節點的情況。 - 採用 C++ 編寫程式碼的時候,忘記要從記憶體中刪除移除的節點,清理節點記憶體。
最終程式碼如下:
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode() : val(0), next(nullptr) {}
* ListNode(int x) : val(x), next(nullptr) {}
* ListNode(int x, ListNode *next) : val(x), next(next) {}
* };
*/
class Solution {
public:
ListNode* removeElements(ListNode* head, int val) {
while(head != nullptr && head->val == val)
{
head = head->next;
}
ListNode *dummy = new ListNode(0);
dummy->next = head;
ListNode* walk = dummy;
while(walk->next != nullptr)
{
if(walk->next->val == val)
{
ListNode *tmp = walk->next;
walk->next = tmp->next;
delete tmp;
}
else
{
walk = walk->next;
}
}
ListNode *newHead = dummy->next;
delete dummy;
return newHead;
}
};
707.設計連結串列
題目連結:https://leetcode.cn/problems/design-linked-list/
題目難度:中等
文章講解:https://programmercarl.com/0707.設計連結串列.html
影片講解: https://www.bilibili.com/video/BV1FU4y1X7WD
題目狀態:思路混亂,看卡哥程式碼
最終程式碼如下:
class MyLinkedList {
public:
struct LinkedNode {
int val;
LinkedNode *next;
LinkedNode(int val)
: val(val)
, next(nullptr)
{}
};
MyLinkedList() {
_dummyHead = new LinkedNode(0);
_size = 0;
}
int get(int index) {
if(index >= _size || index < 0) return -1;
LinkedNode *cur = _dummyHead->next;
while(index--) {
cur = cur->next;
}
return cur->val;
}
void addAtHead(int val) {
LinkedNode *newNode = new LinkedNode(val);
newNode->next = _dummyHead->next;
_dummyHead->next = newNode;
_size++;
}
void addAtTail(int val) {
LinkedNode *newNode = new LinkedNode(val);
LinkedNode *cur = _dummyHead;
while(cur->next != nullptr) {
cur = cur->next;
}
cur->next = newNode;
_size++;
}
void addAtIndex(int index, int val) {
if(index > _size) return;
if(index < 0) index = 0;
LinkedNode *cur = _dummyHead;
LinkedNode *newNode = new LinkedNode(val);
while(index--) {
cur = cur->next;
}
newNode->next = cur->next;
cur->next = newNode;
_size++;
}
void deleteAtIndex(int index) {
if(index >= _size || index < 0) return;
LinkedNode *cur = _dummyHead;
while(index--) {
cur = cur->next;
}
LinkedNode *tmp = cur->next;
cur->next = tmp->next;
delete tmp;
tmp = nullptr;
_size--;
}
private:
int _size;
LinkedNode *_dummyHead;
};
/**
* Your MyLinkedList object will be instantiated and called as such:
* MyLinkedList* obj = new MyLinkedList();
* int param_1 = obj->get(index);
* obj->addAtHead(val);
* obj->addAtTail(val);
* obj->addAtIndex(index,val);
* obj->deleteAtIndex(index);
*/
⚠️注意:
在deleteAtIndex
介面中使用delete
釋放了tmp
指標原本所指的那部分記憶體,但是被delete
後的指標tmp
的值並不是nullptr
,而是隨機值,即tmp
成為了野指標,因此需要將tmp = nullptr
。
206.反轉連結串列
題目連結:https://leetcode.cn/problems/reverse-linked-list/
題目難度:簡單
文章講解:https://programmercarl.com/0206.翻轉連結串列.html
影片講解: https://www.bilibili.com/video/BV1nB4y1i7eL
題目狀態:透過
個人思路:
構建一個新連結串列用於儲存反轉後的連結串列,再迴圈舊的連結串列,每迴圈到一個節點,就將該節點的值採用頭插法插入到新連結串列中,最後返回新連結串列。
實現程式碼:
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode() : val(0), next(nullptr) {}
* ListNode(int x) : val(x), next(nullptr) {}
* ListNode(int x, ListNode *next) : val(x), next(next) {}
* };
*/
class Solution {
public:
ListNode* reverseList(ListNode* head) {
if(head == nullptr) return head;
ListNode *newList = new ListNode();
ListNode *cur = head;
while(cur != nullptr) {
ListNode *tmp = new ListNode(cur->val);
tmp->next = newList->next;
newList->next = tmp;
cur = cur->next;
}
return newList->next;
}
};
過是過了,但看著那兩個大大的new
並且沒有delete
我就噁心,感覺自己又寫了一坨……
其他思路:
1. 雙指標法
a. 直接定義兩個指標cur
和pre
,cur
用於遍歷,pre
用於儲存cur
的前一個節點。
b. 每次遍歷到下一個節點的時候,cur
就會將它的下一個節點的指向指到自己的前一個節點pre
,最後更新自己到原本的下一個節點。
程式碼:
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode() : val(0), next(nullptr) {}
* ListNode(int x) : val(x), next(nullptr) {}
* ListNode(int x, ListNode *next) : val(x), next(next) {}
* };
*/
class Solution {
public:
ListNode* reverseList(ListNode* head) {
if(head == nullptr) return head;
ListNode *cur = head;
ListNode *pre = nullptr;
ListNode *tmp;
while(cur != nullptr) {
tmp = cur->next;
cur->next = pre;
pre = cur;
cur = tmp;
}
return pre;
}
};
2. 遞迴法
思路和雙指標法相同,程式碼如下:
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode() : val(0), next(nullptr) {}
* ListNode(int x) : val(x), next(nullptr) {}
* ListNode(int x, ListNode *next) : val(x), next(next) {}
* };
*/
class Solution {
public:
ListNode* reverseList(ListNode* head) {
return reverse(nullptr, head);
}
ListNode *reverse(ListNode *pre, ListNode *cur) {
if(cur == nullptr) return pre;
ListNode *tmp = cur->next;
cur->next = pre;
return reverse(cur, tmp);
}
};
還有種思路但是沒看懂:
從後往前翻轉指標指向
class Solution {
public:
ListNode* reverseList(ListNode* head) {
// 邊緣條件判斷
if(head == NULL) return NULL;
if (head->next == NULL) return head;
// 遞迴呼叫,翻轉第二個節點開始往後的連結串列
ListNode *last = reverseList(head->next);
// 翻轉頭節點與第二個節點的指向
head->next->next = head;
// 此時的 head 節點為尾節點,next 需要指向 NULL
head->next = NULL;
return last;
}
};