文档讲解:代码随想录 (programmercarl.com)
视频讲解:手把手带你学会操作链表 | LeetCode:203.移除链表元素_哔哩哔哩_bilibili
状态:没写出来
一开始看是简单题,尝试了二十分钟,部分用例没过,直接看解析。发现忽略了移除头结点的情况,因为移除头结点和移除中间结点的代码不一样,移除头结点的逻辑是head = head->next,即头结点直接向后平移,而移除中间结点的的逻辑是cur->next = cur->next->next。
仔细读题发现,题目中所给的头结点是有实际意义的,就是说它是整个链表的一部分,而并没有给出头结点的前一个结点。这里纠结这个指向头结点的结点的原因是,在学习数据结构与算法这门课程中,链表的数据结构中往往有一个没有实际意义的头结点,这个结点就是以下算法中的关键,即虚拟头结点。
这样一来,就可以在这个题目的链表中,插入一个虚拟头结点,这样做的好处是可以使移除链表的逻辑统一,进而实现代码的统一。就再也不用考虑移除头结点的情况了!
class Solution {
public:
ListNode* removeElements(ListNode* head, int val) {
ListNode* dummyhead = new ListNode();
dummyhead->next = head;
ListNode* cur = dummyhead;
while(cur->next != nullptr){
if(cur->next->val == val){
ListNode* tmp = cur->next;
cur->next = cur->next->next;
delete tmp;
}else{
cur = cur->next;
}
}
return dummyhead->next;
}
};
文档讲解:代码随想录 (programmercarl.com)
视频讲解:帮你把链表操作学个通透!LeetCode:707.设计链表_哔哩哔哩_bilibili
状态:会写方法不会定义
数据结构与算法的知识都忘得差不多了,搞得我连怎么初始化都搞错。
但是操作的方法都能写出来,唯一要注意的就是,index>size-1和index>size为什么要这样判定。
class MyLinkedList {
public:
struct ListNode{
int val;
ListNode* next;
ListNode(int val):val(val),next(nullptr){}
};
MyLinkedList() {
dummyhead = new ListNode(0);
size = 0;
}
int get(int index) {
if(index < 0 || index > size - 1)return -1;
ListNode* cur = dummyhead;
for(int i = 0;i < index;i++){
cur = cur->next;
}
return cur->next->val;
}
void addAtHead(int val) {
ListNode* cur = new ListNode(val);
cur->next = dummyhead->next;
dummyhead->next = cur;
size++;
}
void addAtTail(int val) {
ListNode* up = dummyhead;
while(up->next != nullptr){
up = up->next;
}
ListNode* cur = new ListNode(val);
cur->next = up->next;
up->next = cur;
size++;
}
void addAtIndex(int index, int val) {
if(index < 0 || index > size)return;
ListNode* cur = dummyhead;
for(int i = 0;i < index;i++){
cur = cur->next;
}
ListNode* up = new ListNode(val);
up->next = cur->next;
cur->next = up;
size++;
}
void deleteAtIndex(int index) {
if(index < 0 || index > size-1)return;
ListNode* cur = dummyhead;
for(int i = 0;i < index;i++){
cur = cur->next;
}
ListNode* tmp = cur->next;
cur->next = cur->next->next;
delete tmp;
size--;
}
private:
int size;
ListNode* dummyhead;
};
文档讲解:代码随想录 (programmercarl.com)
视频讲解:帮你拿下反转链表 | LeetCode:206.反转链表 | 双指针法 | 递归法_哔哩哔哩_bilibili
状态:直接看的视频
自己尝试做了几分钟,发现思路不太清晰,索性直接看视频讲解了。后来想到可以用头插法来解,但是跟视频上做法不一样,于是就没有尝试。看完视频后,顺着思路,写了双指针法版本和递归版本,递归版本可以对着双指针法的代码去理解,特别是在pre和cur移动的部分,真的太好懂了。
非递归版本:
class Solution {
public:
ListNode* reverseList(ListNode* head) {
ListNode* cur = head;
ListNode* pre = nullptr;
while(cur != nullptr){
ListNode* tmp = cur->next;
cur->next = pre;
pre = cur;
cur = tmp;
}
return pre;
}
};
递归版本:
class Solution {
public:
ListNode* reverse(ListNode* pre,ListNode* cur){
if(cur == nullptr)return pre;
ListNode* tmp = cur->next;
cur->next = pre;
return reverse(cur,tmp);
}
ListNode* reverseList(ListNode* head) {
return reverse(nullptr,head);
}
};