前言
链表题公式解:链表转数组->操作数组->数组转链表
打卡第三天~
今天是链表专题~
链表
什么是链表
今天将结束数组,开始链表的学习,那么对于链表,他的结构与特点相比较数组还是有很大的差距的;
- 什么是链表
链表是一种通过指针串联在一起的线性结构,每一个节点由两部分组成,一个是数据域一个是指针域(存放指向下一个节点的指针),最后一个节点的指针域指向null(空指针)。
链表的入口节点称为链表的头结点也就是head。
- 链表的内存管理
数组是在内存中是连续分布的,但是链表在内存中可不是连续分布的。
链表是通过指针域的指针链接在内存中各个节点。
所以链表中的节点在内存中不是连续分布的 ,而是散乱分布在内存中的某地址上,分配机制取决于操作系统的内存管理。
如图所示
- 链表-链表与数据性能对比
数组在定义的时候,长度就是固定的,如果想改动数组的长度,就需要重新定义一个新的数组。
链表的长度可以是不固定的,并且可以动态增删, 适合数据量不固定,频繁增删,较少查询的场景。
接下来进入正题,刷题环节~
LeetCode 203. 移除链表元素
203. 移除链表元素
文章讲解
视频讲解
状态 : AC
看到这题,我首先想到了之前做的题目 LeetCode 27 移除元素 其区别只在于,一个是操作链表,一个是操作数组
那么是不是可以先将链表元素存入数组中,再操作数组,最后转换为链表呢
这就是链表题的一种通解
- AC代码示例:
class Solution {
public:
ListNode* removeElements(ListNode* head, int s) {
ListNode *p=head;
vector <int> nums;
// 一 将链表元素存入数组
while(p){
nums.push_back(p->val);
p=p->next;
}
// 二 对数组进行相应操作
int slow=-1,fast=0;
while(fast<nums.size()){
if(slow<fast && nums[fast]!=s){
slow++;
nums[slow]=nums[fast];
}
fast++;
}
// 三 再转换为链表
if(slow+1>0)
head->val=nums[0];
else return nullptr;
head->next=nullptr;
p=head;
for(int i=1;i<slow+1;i++){
ListNode *Next=new ListNode(nums[i]);
p->next=Next;
p=p->next;
}
return head;
}
};
- 时间复杂度:O(n)
- 空间复杂度:O(n) (开辟数组空间)
LeetCode 707. 设计链表
LeetCode 707. 设计链表
文章讲解
视频讲解
状态 : Debug 半小时 终于A了
这一题就得老老实实的掌握链表了
题目还是不错的,一题涉及了链表的增删改(?)查
看见就上手一顿操作,然后报错www,主要是index下标的问题
最后慢慢debug才整出来,但原来的太丑了
再看卡哥的讲解…自己重新写了一份
- AC代码示例:
class MyLinkedList {
struct myList{
int val;
myList* next;
myList():val(0),next(nullptr){}
myList(int a):val(a),next(nullptr){}
myList(int a, myList* next_a):val(a),next(next_a){}
};
public:
MyLinkedList(){
listhead=new myList(0);
list_size=0;
}
int get(int index) {
if(index>=list_size) return -1;
int count=0;
myList* pmove=listhead;
while(count != index){
count++;
pmove=pmove->next;
}
return pmove->val;
}
void addAtHead(int val) {
if(list_size==0){
myList* newnode=new myList(val);
listhead=newnode;
list_size++;
return;
}
myList* newnode=new myList(val);
newnode->next=listhead;
listhead=newnode;
list_size++;
}
void addAtTail(int val) {
if(list_size==0){
myList* newnode=new myList(val);
listhead=newnode;
list_size++;
return;
}
myList* pmove=listhead;
while(pmove->next){
pmove=pmove->next;
}
myList* newnode=new myList(val);
pmove->next=newnode;
list_size++;
}
void addAtIndex(int index, int val) {
if(index>list_size) return;
if(index==0){
addAtHead(val);
return;
}
int count=0;
myList* pmove=listhead;
while(count+1 != index){
count++;
pmove=pmove->next;
}
list_size++;
myList* newnode=new myList(val,pmove->next);
pmove->next=newnode;
}
void deleteAtIndex(int index) {
if(index>=list_size) return;
int count=0;
myList* pmove=listhead;
if(index==0){
listhead=listhead->next;
list_size--;
return;
}
while(count+1 != index){
count++;
pmove=pmove->next;
}
pmove->next=pmove->next->next;
list_size--;
}
int list_size;
myList* listhead;
};
- 时间复杂度: 涉及 index 的相关操作为 O(index), 其余为 O(1)
- 空间复杂度: O(n)
LeetCode 206. 反转链表
LeetCode 206. 反转链表
文章讲解
视频讲解
状态 : 2分钟搞定
这题就能用公式搞定
链表转数组->操作数组->数组转链表
但建议还是手写一遍常规解,毕竟学习的是链表嘛!
- AC代码示例(公式解):
class Solution {
public:
ListNode* reverseList(ListNode* head) {
ListNode *pmove=head;
vector<int >nums;
//一. 链表转数组
while(pmove){
nums.push_back(pmove->val);
pmove=pmove->next;
}
//二. 操作数组
reverse(nums.begin(),nums.end());
//三. 数组转链表
if(nums.size()>0)
head->val=nums[0];
else return nullptr;
head->next=nullptr;
pmove=head;
for(int i=1;i<nums.size();i++){
ListNode *Next=new ListNode(nums[i]);
pmove->next=Next;
pmove=pmove->next;
}
return head;
}
};
- 时间复杂度: O(n)
- 空间复杂度: O(n) (开辟数组)
当然常规解也是要学习的~
- AC代码示例(公式解):
class Solution {
public:
ListNode* reverseList(ListNode* head) {
ListNode* temp;
ListNode* cur = head;
ListNode* pre = NULL;
while(cur) {
temp = cur->next;
cur->next = pre;
pre = cur;
cur = temp;
}
return pre;
}
};
- 时间复杂度: O(n)
- 空间复杂度: O(1)
总结
坚持
2024- 4-19