代码随想录算法训练营day3 | 203.移除链表元素 707.设计链表 206.反转链表
链表理论基础
单链表
链表是一种通过指针串联在一起的线性结构,每一个节点由两部分组成,一个是数据域,一个是指针域(指向下一个节点),最后一个指针域指向NULL(空节点)。
双链表
单链表中的指针域只能指向节点的下一个节点。
双链表:每一个节点有两个指针域,一个指向下一个节点,一个指向上一个节点。
双链表 既可以向前查询也可以向后查询。
链表的存储方式
链表不是像指针一样在内存中是连续分布的,是散落分布的,分配机制取决于操作系统的内存管理。
循环链表
循环链表,顾名思义,就是链表首尾相连。
循环链表可以用来解决约瑟夫环问题。
性能分析
插入/删除(时间复杂度 | 查询(时间复杂度) | 适用场景 | |
---|---|---|---|
数组 | O(n) | O(1) | 数据量固定,频繁查找,较少增删 |
链表 | O(1) | O(n) | 数据量不定,较少查找,频繁增删 |
刷题笔记day3
203.移除链表元素
文章讲解:代码随想录
是否自己做出来通过全部用例:否
遇到的困难/犯的错误
while (temp != NULL && temp->val == val)
temp != NULL应该放在前面,不然NULL->val会报错。
一定要delete掉要删除的节点。
在原链表进行删除需要两个while循环,但是如果造一个虚拟头节点可以只需要一次while循环。
动态分配的内存指针同样要用动态分配的内存指针才能去赋值。
自己写的代码
看了题解后用虚拟头节点法写的代码:
class Solution {
public:
ListNode* removeElements(ListNode* head, int val) {
if (head == NULL) {
return NULL;
}
ListNode* virhead = new ListNode(0);
virhead->next = head;
ListNode* cur = virhead;
while (cur->next != NULL) {
if (cur->next->val == val) {
ListNode* temp = cur->next;
cur->next = cur->next->next;
delete temp;
}
else {
cur = cur->next;
}
}
return virhead->next;
}
};
看了题解后的收获
在原链表进行删除需要两个while循环,但是如果造一个虚拟头节点可以只需要一次while循环。
动态分配的内存指针同样要用动态分配的内存指针才能去赋值。
707.设计链表
文章讲解:代码随想录
是否自己做出来通过全部用例:是
遇到的困难/犯的错误
选择了直接用原链表进行操作,碰到了很多坑。主要是_size在计算过程中的错误。按题意,new了一个之后_size=0,但是实际已经=1,所以导致添加元素删减元素时都要加上一些条件判断。
自己写的代码
研究了大概一个多小时写出来的代码:
class MyLinkedList {
public:
MyLinkedList() {
_head = new LinkedNode(0);
_size = 0;
}
int get(int index) {
if (index < 0 || index > _size - 1) {
return -1;
}
LinkedNode* cur = _head;
if (index == 0) {
return cur->val;
}
else {
for (int i = 1; i <= index; ++i) {
cur = cur->next;
}
}
return cur->val;
}
void addAtHead(int val) {
LinkedNode* newhead = new LinkedNode(val);
if (_size == 0) {
_head = newhead;
}
else {
newhead->next = _head;
_head = newhead;
}
++_size;
}
void addAtTail(int val) {
LinkedNode* newtail = new LinkedNode(val);
if (_size == 0) {
_head = newtail;
}
else {
LinkedNode* cur = _head;
while (cur->next != NULL) {
cur = cur->next;
}
cur->next = newtail;
}
++_size;
}
void addAtIndex(int index, int val) {
if (index > _size || index < 0) {
return;
}
if (index == 0) {
addAtHead(val);
}
else {
int counts = 0;
LinkedNode* cur = _head;
while (cur->next != NULL)
{
++counts;
if (counts == index) {
LinkedNode* newnode = new LinkedNode(val);
newnode->next = cur->next;
cur->next = newnode;
++_size;
return;
}
cur = cur->next;
}
if (index == counts + 1) {
addAtTail(val);
}
if (index > counts + 1) {
return;
}
}
}
void deleteAtIndex(int index) {
if (index < 0 || index > _size - 1)
{
return;
}
if (index == 0) {
LinkedNode* temp = _head;
_head = _head->next;
delete temp;
}
else {
LinkedNode* cur = _head;
int counts = 0;
while (cur->next != NULL) {
++counts;
if (counts == index) {
LinkedNode* temp = cur->next;
cur->next = cur->next->next;
break;
}
cur = cur->next;
}
}
--_size;
}
private:
struct LinkedNode {
int val;
LinkedNode* next;
LinkedNode(int val): val(val), next(nullptr){}
};
int _size;
LinkedNode* _head;
};
看了题解后的收获
看了题解后自己手撕了一遍用虚拟头节点的版本:
class MyLinkedList {
public:
MyLinkedList() {
_dummyhead = new LinkedNode(0);
_size = 0;
}
int get(int index) {
if (index > _size - 1 || index < 0) {
return -1;
}
LinkedNode* cur = _dummyhead->next;
while (index--) {
cur = cur->next;
}
return cur->val;
}
void addAtHead(int val) {
LinkedNode* node = new LinkedNode(val);
node->next = _dummyhead->next;
_dummyhead->next = node;
++_size;
}
void addAtTail(int val) {
LinkedNode* cur = new LinkedNode(val);
LinkedNode* temp = _dummyhead;
while (temp->next != NULL) {
temp = temp->next;
}
temp->next = cur;
++_size;
}
void addAtIndex(int index, int val) {
if (index > _size|| index < 0) {
return;
}
LinkedNode* cur = new LinkedNode(val);
LinkedNode* temp = _dummyhead;
while (index--) {
temp = temp->next;
}
cur->next = temp->next;
temp->next = cur;
++_size;
}
void deleteAtIndex(int index) {
if (index > _size - 1 || index < 0) {
return;
}
LinkedNode* cur = _dummyhead;
while (index--) {
cur = cur->next;
}
LinkedNode* temp = cur->next;
cur->next = cur->next->next;
delete temp;
--_size;
}
private:
struct LinkedNode {
int val;
LinkedNode* next;
LinkedNode(int val): val(val), next(nullptr){}
};
int _size;
LinkedNode* _dummyhead;
};
如果使用虚拟头节点真的简单很多!主要是更容易符合题意。如果题意new后的初始_size = 1,那应该会简单很多。
206.反转链表
文章讲解:代码随想录
是否自己做出来通过全部用例:否
遇到的困难/犯的错误
循环条件应该是:while (temp->next != NULL)
循环条件有问题。
看了题解后的收获
掌握了本题的双指针解法。