代码随想录算法训练营第三天 链表 | 203.移除链表元素 | 707.设计链表 | 206.反转链表
链表
链表是一种线性结构,不同于使用连续空间的储存结构(vector,数组,string等),链表在内存中的储存方式并不是连续分布的,分配散乱,分配机制取决于操作系统的内存管理。
C++中定义链表节点的方式
// 单链表
struct ListNode {
int val; // 节点上存储的元素
ListNode *next; // 指向下一个节点的指针
ListNode(int x) : val(x), next(NULL) {} // 节点的构造函数
};
链表中删除和添加元素都是通过改变相邻节点指针指向的节点来完成,时间复杂度是
链表操作 lc203 移除链表元素
使用虚拟头指针来统一删除操作,避免对头指针为目标值的情况特殊处理
/**
* 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) {
ListNode* dummy_head = new ListNode(0,head);
ListNode* cur = dummy_head;
while(cur->next != NULL){
if (cur->next->val == val){
ListNode* tmp = cur->next;
cur->next = cur->next->next;
delete tmp;
}
else{
cur = cur->next;
}
}
return dummy_head->next;
}
};
链表操作 lc707 设计链表
这道题基本包含了所有链表的操作。难点在于对链表增删查的理解,删改时操作的顺序,cur当前指针应该从虚拟头指针开始还是从头指针开始。
目前总结下来,使用虚拟头指针时
- 增删时,先将新节点的next指好,再将目标位置前节点的next指向新节点,以防找不到新节点指向的位置
- 增删时,需要保留目标位置前一个位置的节点信息,所以cur当前指针应该从虚拟头指针开始,
cur->next
为我们想要删除或增加的位置
class MyLinkedList {
public:
//链表节点结构体
struct LinkedNode{
int val;
LinkedNode* next;
LinkedNode(int val) : val(val), next(nullptr){}
};
MyLinkedList() {
_size = 0;
_dummy_head = new LinkedNode(0);
}
int get(int index) {
if (index < 0 || index > _size-1){
return -1;
}
LinkedNode* cur = _dummy_head->next;
while(index--){
cur = cur->next;
}
return cur->val;
}
void addAtHead(int val) {
LinkedNode* newnode = new LinkedNode(val);
newnode->next = _dummy_head->next;
_dummy_head->next = newnode;
_size++;
}
void addAtTail(int val) {
LinkedNode* newnode = new LinkedNode(val);
LinkedNode* cur = _dummy_head;
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 = _dummy_head;
LinkedNode* newnode = new LinkedNode(val);
while(index--){
cur = cur->next;
}
newnode->next = cur->next;
cur->next = newnode;
_size++;
}
void deleteAtIndex(int index) {
if (index < 0 || index > _size-1){
return;
}
LinkedNode* cur = _dummy_head;
while(index--){
cur = cur->next;
}
LinkedNode* tmp = cur->next;
cur->next = cur->next->next;
delete tmp;
_size--;
}
private: //private 中的数据成员命名时前面加了'_',用来与其他变量进行区分。
int _size;
LinkedNode* _dummy_head;
};
/**
* 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);
*/
双指针、递归 lc206 反转链表
双指针
需要一个临时指针来存放原本的cur->next
,迭代赋值时要注意先给pre赋值,不然会丢失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) {
ListNode* pre = nullptr;
ListNode* cur = head;
while(cur){
ListNode* tmp = cur->next;
cur->next = pre;
pre = cur;
cur = tmp;
}
return 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) {
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);
}
};
Extra
leetcode评论区里的写法,时间空间复杂度都是
/**
* 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) {
ListNode* ans = nullptr;
for (ListNode* i=head;i!=nullptr;i=i->next){
ans = new ListNode(i->val,ans);
}
return ans;
}
};
本文作者:冰镇杨梅
本文链接:https://www.cnblogs.com/frozenwaxberry/p/17051082.html
版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步