算法打卡|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数据结构和算法(七)——链表
前面博客我们在讲解数组中,知道数组作为数据存储结构有一定的缺陷.在无序数组中,搜索性能差,在有序数组中,插入效率又很低,而且这两种数组的删除效率都很低,并且数组在创建后,其大小是固定了,设置的过大会造 ...
随机推荐
- jvm中类和对象定义存储基础知识
1 类文件数据结构类型 Class文件结构主要有两种数据结构:无符号数和表 •无符号数:用来表述数字,索引引用.数量值以及字符串等,比如 图1中类型为u1,u2,u4,u8分别代表1个字节,2个字节, ...
- 20200411 联想Yoga 2 13升级大SSD
20200411:下文的操作实际发生在2018年11月,当时完成了就写好了这篇文章,却忘了放上来,最近家里一个电脑的硬盘坏了,来翻箱底才找到,现在发上来. 原配置:Lonevo Yoga2 13,唯一 ...
- CKS 考试题整理 (03)-kube-bench 修复不安全项
Context 针对 kubeadm 创建的 cluster 运行 CIS 基准测试工具时,发现了多个必须立即解决的问题. Task 通过配置修复所有问题并重新启动受影响的组件以确保新的设置生效. 修 ...
- vue前端预览pdf并加水印、ofd文件,控制打印、下载、另存,vue-pdf的使用方法以及在开发中所踩过的坑合集
根据公司的实际项目需求,要求实现对pdf和ofd文件的预览,并且需要限制用户是否可以下载.打印.另存pdf.ofd文件,如果该用户可以打印.下载需要控制每个用户的下载次数以及可打印的次数.正常的预览p ...
- 前端vue自定义简单实用下拉筛选 下拉菜单
前端vue自定义简单实用下拉筛选 下拉菜单, 下载完整代码请访问: https://ext.dcloud.net.cn/plugin?id=13020 效果图如下: #### 使用方法 ``` ...
- 手写数字识别系统Python+CNN卷积神经网络算法【完整代码】
一.介绍 手写数字识别系统,使用Python语言,基于TensorFlow搭建CNN卷积神经网络算法对数据集进行训练,最后得到模型,并基于FLask搭建网页端界面,基于Pyqt5搭建桌面端可视化界面. ...
- 高并发场景下,6种解决SimpleDateFormat类的线程安全问题方法
摘要:解决SimpleDateFormat类在高并发场景下的线程安全问题可以有多种方式,这里,就列举几个常用的方式供参考. 本文分享自华为云社区<[高并发]更正SimpleDateFormat类 ...
- H5 WebGL实现水波特效
前言 零几年刚开始玩电脑的时候,经常在安装程序上看到一种水波特效,鼠标划过去的时候,就像用手在水面划过一样,感觉特别有意思.但是后来,就慢慢很少见过这种特效了.最近突然又想起了这种特效,于是开始折磨怎 ...
- RTC+AI|“即智”数智人创新内容生产体验,为企业降本增效再提速
号称"史上最卷"的618年中大促落下帷幕,几大电商巨头在直播投入和短视频内容建设上持续加码,短视频+直播电商的营销模式成为618期间的主要输出. 以某美妆专场直播间为例,主播现场手 ...
- 即构低延迟直播产品L3,打造更优质的实时互动体验
以短视频.直播为代表的音视频互动,正成为互联网主流的交互方式.拿直播举例,它从一种娱乐形式,逐渐融合于教育.娱乐.电商.旅游等多种生态中.未来,直播还将成为像水.电一样的基础设施. 然而,仅仅可进行音 ...