算法打卡|Day3 链表part01
Day3 链表part01
今日任务
● 链表理论基础
● 203.移除链表元素
● 707.设计链表
● 206.反转链表
链表理论基础
文章链接:https://programmercarl.com/链表理论基础.html
重点:
- 单链表是一种通过指针串联在一起的线性结构,每一个节点由两部分组成,一个是数据域一个是指针域(存放指向下一个节点的指针),最后一个节点的指针域指向null(空指针的意思)。

//单链表实现代码
#include <iostream>
using namespace std;
struct Node
{
int val;
Node* next;
} *head;
int main()
{
for (int i = 1; i <= 5; i ++ )
{
Node* p = new Node();
p->val = i;
p->next = head;
head = p;
}
for (Node* p = head; p; p = p->next)
cout << p->val << ' ';
cout << endl;
return 0;
}
Problem: 203. 移除链表元素
思路
首先最原始的思路是我们可以将头结点和后面的结点分开处理。但是为了逻辑统一我们可以用虚拟头结点的方式删除链表指定元素。
解题方法
虚拟头结点
Code
/**
* 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) {}
* };
*/
/**
时间复杂度: O(n)
空间复杂度: O(1)
*/
class Solution {
public:
ListNode* removeElements(ListNode* head, int val) {
ListNode* dummy = new ListNode(-1);//涉及到单向链表头结点可以用虚拟头结点的技巧
dummy->next = head;
ListNode* i = dummy;
while(i->next!=nullptr){
if(i->next->val == val){
//记住用临时变量保存删除
ListNode* tmp = i->next;
i->next = i->next->next;
delete tmp;
} else{
i = i->next;
}
}
//利用虚拟头结点时候要注意最后真实的头结点是由虚拟头结点确定的,所以要记得更新再释放
head = dummy ->next;
delete dummy;
return head;
}
};
Problem: 707. 设计链表
思路
注意index下标的遍历,然后插入和删除都要在index前一位开始停下操作。
链接:
https://leetcode.cn/problems/design-linked-list/solutions/1738065/by-linken_54-7moa/
Code
class MyLinkedList {
public:
int len;
struct Listnode{
int val;
Listnode* next;
Listnode(): val(0),next(nullptr){}
Listnode(int _val): val(_val),next(nullptr){}
Listnode(int _val, Listnode* _next): val(_val),next(_next){}
};
Listnode* dummynode;
MyLinkedList() {
len = 0;
dummynode = new Listnode();
}
int get(int index) {
if(index<0 || index >len-1) return -1;
Listnode* cur = dummynode->next;//如果从真实头结点开始遍历,那么index--循环就是index所指示的地方
while(index--){
cur = cur->next;
}
return cur->val;
}
void addAtHead(int val) {
if(val<0||val>1000) return;//val值无效,直接返回
Listnode* head=new Listnode(val,dummynode->next);
dummynode->next = head;
len++;
}
void addAtTail(int val) {
if(val<0||val>1000) return;//val值无效,直接返回
Listnode* tail = dummynode;
//遍历尾结点可以直接用tail->next去判断尾结点
while(tail->next){
tail = tail->next;
}
tail->next = new Listnode(val);
len++;
}
void addAtIndex(int index, int val) {
if(val<0||val>1000||index>len) return;//val值或index值无效,直接返回
if(index<=0) addAtHead(val);//index<=0时,在头部插入值为val的新结点
else if(index==len) addAtTail(val);//index=len时,在尾部插入值为val的新结点
else{
Listnode* cur = dummynode;
while(index--) cur=cur->next;
cur->next = new Listnode(val,cur->next);
len++;
}
}
void deleteAtIndex(int index) {
if(index<0||index>len-1) return;//index值无效,直接返回
Listnode* cur = dummynode;//如果从虚拟头结点开始遍历,那么index--循环就是index前一位所指示的地方
while(index--){
cur = cur->next;
}
Listnode* tmp = cur->next;
cur->next = cur->next->next;
delete tmp;
len--;
}
};
/**
* Your MyLinkedList object will be instantiated and called as such:
* MyLinkedList* obj = new Myb LinkedList();
* int param_1 = obj->get(index);
* obj->addAtHead(val);
* obj->addAtTail(val);
* obj->addAtIndex(index,val);
* obj->deleteAtIndex(index);
*/
Code2
class MyLinkedList {
private:
struct Listnode{
int val;
Listnode* next;
Listnode(): val(0),next(nullptr){}
Listnode(int _val): val(_val),next(nullptr){}
Listnode(int _val,Listnode* _node): val(_val), next(_node){}
};
int len;
Listnode* dummyhead;
public:
MyLinkedList(){
len = 0;
dummyhead = new Listnode();
}
int get(int index) {
if(index<0 || index > len-1) return -1;
Listnode* cur = dummyhead->next;
for(int i = 0;i!=index;i++){
cur = cur->next;
}
return cur->val;
}
void addAtHead(int val) {
if(val<0||val>1000) return;
Listnode* node = new Listnode(val, dummyhead->next);
dummyhead->next = node;
len++;
}
void addAtTail(int val) {
if(val<0||val>1000) return;
Listnode* i;
for(i =dummyhead; i->next; i = i->next){}
i->next = new Listnode(val);
len++;
}
void addAtIndex(int index, int val) {
if(val<0||val>1000||index>len) return;
if(index<=0) addAtHead(val);
else if(index==len) addAtTail(val);
else{
Listnode* cur =dummyhead;
for(int i = -1; i!=index-1; i++){
cur = cur->next;
}
cur->next = new Listnode(val,cur->next);
len++;
}
}
void deleteAtIndex(int index) {
if(index<0||index>len-1) return;
Listnode* cur = dummyhead;
for(int i = -1;i!=index-1; i++){
cur = cur->next;
}
Listnode* tmp = cur->next;
cur->next =cur->next->next;
delete tmp;
len--;
}
};
/**
* 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);
*/
Problem: 206. 反转链表
思路
链表题,多画图!
好理解的双指针
1.定义两个指针: pre 和 cur ;pre 在前 cur 在后。
2.每次让 pre 的 next 指向 cur ,实现一次局部反转
3.局部反转完成之后,pre 和 cur 同时往前移动一个位置
4.循环上述过程,直至 pre 到达链表尾部
简洁的递归
1.使用递归函数,一直递归到链表的最后一个结点,该结点就是反转后的头结点,记作 ret .
2.此后,每次函数在返回的过程中,让当前结点的下一个结点的 next 指针指向当前节点。
3.同时让当前结点的 next 指针指向 NULL ,从而实现从链表尾部开始的局部反转
4.当递归函数全部出栈后,链表反转完成。
解题方法
双指针和递归
Code1: 双指针
//时间复杂度: O(n)
//空间复杂度: O(1)
/**
* 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* a = nullptr;
ListNode* b = head;
while(b){
ListNode* tmp = b->next;
b->next = a;
a = b;
b = tmp;
}
return a;
}
};
Code2: 递归法
//时间复杂度: O(n), 要递归处理链表的每个节点
//空间复杂度: O(n), 递归调用了 n 层栈空间
/**
* 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||head->next == nullptr) return head;
else{
ListNode* tail=reverseList(head->next);
head->next->next = head;
head->next =nullptr;
return tail;
}
}
};
算法打卡|Day3 链表part01的更多相关文章
- cc150:实现一个算法来删除单链表中间的一个结点,仅仅给出指向那个结点的指针
实现一个算法来删除单链表中间的一个结点,仅仅给出指向那个结点的指针. 样例: 输入:指向链表a->b->c->d->e中结点c的指针 结果:不须要返回什么,得到一个新链表:a- ...
- 算法:输入一个链表,输出该链表中倒数第k个结点。
算法:输入一个链表,输出该链表中倒数第k个结点.<剑指offer> 思路加到注释里面了: 1:两个if判断是否返回值为空,首个为空,没有第k个值: 2:for循环找到倒数第k个值,返回为a ...
- LeetCode初级算法的Python实现--链表
LeetCode初级算法的Python实现--链表 之前没有接触过Python编写的链表,所以这里记录一下思路.这里前面的代码是和leetcode中的一样,因为做题需要调用,所以下面会给出. 首先定义 ...
- 数据结构与算法之美 06 | 链表(上)-如何实现LRU缓存淘汰算法
常见的缓存淘汰策略: 先进先出 FIFO 最少使用LFU(Least Frequently Used) 最近最少使用 LRU(Least Recently Used) 链表定义: 链表也是线性表的一种 ...
- 算法之python创建链表实现cache
算法之python创建链表实现cache 本节内容 问题由来 解决思路 实现代码 总结 1. 问题由来 问题起因于朋友的一次面试题,面试公司直接给出两道题,要求四十八小时之内做出来,语言不限,做出来之 ...
- JavaScript 版数据结构与算法(三)链表
今天,我们要讲的是数据结构与算法中的链表. 链表简介 链表是什么?链表是一种动态的数据结构,这意味着我们可以任意增删元素,它会按需扩容.为何要使用链表?下面列举一些链表的用途: 因为数组的存储有缺陷: ...
- 实用算法系列之RT-Thread链表堆管理器
[导读] 前文描述了栈的基本概念,本文来聊聊堆是怎么会事儿.RT-Thread 在社区广受欢迎,阅读了其内核代码,实现了堆的管理,代码设计很清晰,可读性很好.故一方面了解RT-Thread内核实现,一 ...
- 数据结构和算法 c#– 1.单项链表
1.顺序存储结构 Array 1.引用类型(托管堆) 2.初始化时会设置默认值 2.链式存储结构 2.1.单向链表 2.2.循环链表 2.3.双向链表
- 008实现一个算法从一个单链表中返回倒数第n个元素(keep it up)
我们维护两个指针, 它们之间的距离为n. 然后.我将这两个指针同步地在这个单链表上移动,保持它们的距离 为n不变. 那么, 当第二个指针指到空时.第一个指针即为所求. #include <ios ...
- Java数据结构和算法(七)——链表
前面博客我们在讲解数组中,知道数组作为数据存储结构有一定的缺陷.在无序数组中,搜索性能差,在有序数组中,插入效率又很低,而且这两种数组的删除效率都很低,并且数组在创建后,其大小是固定了,设置的过大会造 ...
随机推荐
- ChatGPT 时代,程序员的生存之道 | 人工智能 AI
前言 ChatGPT 近期炙手可热,仿佛没有什么问题是它不能解决的.出于对 ChatGPT 的好奇,我们决定探索下它对于前端开发人员来讲,是作为辅助工具多一些,还是主力工具更多一些? 2D 能力测试 ...
- elementUi+table实现表格数据滚动
elementUi+table实现表格数据滚动 引用vue和elementUI CDN // 引用elementUI CDN <script src="https://unpkg.co ...
- C/S架构和B/S架构两种数字孪生技术路线的区别是什么?
山海鲸创造了一种CS和BS热切换的编辑模式,即CSaaS架构,可以在安装软件之后一键从软件的CS状态切换为一个BS服务器,让私有化部署变得十分轻松.具体效果可以参照下面的视频: (https://ww ...
- 2023-06-23:redis中什么是缓存击穿?该如何解决?
2023-06-23:redis中什么是缓存击穿?该如何解决? 答案2023-06-23: 缓存击穿是指一个缓存中的热点数据非常频繁地被大量并发请求访问,当该热点数据失效的瞬间,持续的大并发请求无法通 ...
- AR技术的应用与未来
目录 随着科技的不断进步,增强现实(AR)技术也在不断发展壮大.AR技术是一种通过计算机技术和传感器技术将虚拟信息融合到现实世界中的技术,可以为用户带来一种全新的.交互性更强的体验.本文将探讨AR技术 ...
- vCenter报错:Vmware vAPI Endpoint
vCenter报错:Vmware vAPI Endpoint 问题现象: 平台警报1:设备管理运行状况警报 平台警报2:Vmware vAPI Endpoint服务运行状况警报 vcenter版本:v ...
- PostgreSQL 12 文档: 前言
前言 目录 1. 何为PostgreSQL? 2. PostgreSQL简史 2.1. 伯克利的POSTGRES项目 2.2. Postgres95 2.3. PostgreSQL 3. 约定 4. ...
- python图表展示实例
"""Created on Fri Nov 8 16:09:36 2019 @author: DELL""" ""&qu ...
- 如何在 Windows10 Professional 服务器上搭建自己的 Git 服务器。
一.简介 以前,在别家的公司,一般早就把源代码管理工具搭建好了,很少有机会自己搭建一套.最近,公司也许要把现在不少的源码进行管理,于是我打算自己搭建源代码管理服务器.说起源代码管理,当然有很多中解决方 ...
- 在映客的虚拟KTV里唱了一首“爱你”
如果你突然打了个喷嚏 那一定就是我在想你 如果半夜被手机吵醒 啊~那是你的虚拟 KTV 在响起 2022 年 5 月 18 日,映客 App 上线了业内首个元宇宙 K 歌玩法「全景 K 歌」,给用 ...