Day3 链表part01

今日任务

● 链表理论基础

● 203.移除链表元素

● 707.设计链表

● 206.反转链表



链表理论基础

文章链接:https://programmercarl.com/链表理论基础.html

重点:

  1. 单链表是一种通过指针串联在一起的线性结构,每一个节点由两部分组成,一个是数据域一个是指针域(存放指向下一个节点的指针),最后一个节点的指针域指向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.当递归函数全部出栈后,链表反转完成。

链接:https://leetcode.cn/problems/reverse-linked-list/solutions/99711/fan-zhuan-lian-biao-shuang-zhi-zhen-di-gui-yao-mo-/

解题方法

双指针和递归

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的更多相关文章

  1. cc150:实现一个算法来删除单链表中间的一个结点,仅仅给出指向那个结点的指针

    实现一个算法来删除单链表中间的一个结点,仅仅给出指向那个结点的指针. 样例: 输入:指向链表a->b->c->d->e中结点c的指针 结果:不须要返回什么,得到一个新链表:a- ...

  2. 算法:输入一个链表,输出该链表中倒数第k个结点。

    算法:输入一个链表,输出该链表中倒数第k个结点.<剑指offer> 思路加到注释里面了: 1:两个if判断是否返回值为空,首个为空,没有第k个值: 2:for循环找到倒数第k个值,返回为a ...

  3. LeetCode初级算法的Python实现--链表

    LeetCode初级算法的Python实现--链表 之前没有接触过Python编写的链表,所以这里记录一下思路.这里前面的代码是和leetcode中的一样,因为做题需要调用,所以下面会给出. 首先定义 ...

  4. 数据结构与算法之美 06 | 链表(上)-如何实现LRU缓存淘汰算法

    常见的缓存淘汰策略: 先进先出 FIFO 最少使用LFU(Least Frequently Used) 最近最少使用 LRU(Least Recently Used) 链表定义: 链表也是线性表的一种 ...

  5. 算法之python创建链表实现cache

    算法之python创建链表实现cache 本节内容 问题由来 解决思路 实现代码 总结 1. 问题由来 问题起因于朋友的一次面试题,面试公司直接给出两道题,要求四十八小时之内做出来,语言不限,做出来之 ...

  6. JavaScript 版数据结构与算法(三)链表

    今天,我们要讲的是数据结构与算法中的链表. 链表简介 链表是什么?链表是一种动态的数据结构,这意味着我们可以任意增删元素,它会按需扩容.为何要使用链表?下面列举一些链表的用途: 因为数组的存储有缺陷: ...

  7. 实用算法系列之RT-Thread链表堆管理器

    [导读] 前文描述了栈的基本概念,本文来聊聊堆是怎么会事儿.RT-Thread 在社区广受欢迎,阅读了其内核代码,实现了堆的管理,代码设计很清晰,可读性很好.故一方面了解RT-Thread内核实现,一 ...

  8. 数据结构和算法 c#– 1.单项链表

    1.顺序存储结构 Array 1.引用类型(托管堆) 2.初始化时会设置默认值   2.链式存储结构 2.1.单向链表 2.2.循环链表 2.3.双向链表

  9. 008实现一个算法从一个单链表中返回倒数第n个元素(keep it up)

    我们维护两个指针, 它们之间的距离为n. 然后.我将这两个指针同步地在这个单链表上移动,保持它们的距离 为n不变. 那么, 当第二个指针指到空时.第一个指针即为所求. #include <ios ...

  10. Java数据结构和算法(七)——链表

    前面博客我们在讲解数组中,知道数组作为数据存储结构有一定的缺陷.在无序数组中,搜索性能差,在有序数组中,插入效率又很低,而且这两种数组的删除效率都很低,并且数组在创建后,其大小是固定了,设置的过大会造 ...

随机推荐

  1. CSS 图片加载提前占位 padding-top、padding-bottom

    今天聊一个图片加载提前占位的一个问题 ,内容比较适合初学者. 起因 在响应式页面当中,图片加载之前是不知道图片高度的,加载成功图片完全撑开.如果不做提前占位会把下面的内容挤下去,页面出现抖动,就像下面 ...

  2. Junit执行器Runner探索之旅

    单元测试是每个程序员必备的技能,而Runner是每个单元测试类必有属性.本文通过解读Junit源码,介绍junit中每个执行器的使用方法,让读者在单元测试时,可以灵活的使用Runner执行器. 一.背 ...

  3. CentOs7安装部署Sonar环境(JDK1.8+MySql5.7+sonarqube7.8)

    sonarqube安装前环境准备JDK1.8.MySql5.7. 一.JDK安装 1.下载jdk #打开下面的网址,选择 jdk-8u371-linux-x64.tar.gz 进行下载 (8u371版 ...

  4. AB实验:科学归因与增长的利器

    第一章 AB实验的基本原理和应用 AB实验的相关概念: 3个基本参数:实验参与单元.实验控制参数.实验指标 2个核心价值:验证因果关系.量化策略效果 2个关键特性:先验性.并行性 基本流程:分流 -& ...

  5. ResNet模型:在计算机视觉任务中实现深度学习

    目录 1. 引言 2. 技术原理及概念 2.1 基本概念解释 2.2 技术原理介绍 3. 实现步骤与流程 3.1 准备工作:环境配置与依赖安装 3.2 核心模块实现 3.3 集成与测试 4. 示例与应 ...

  6. Github的一个彩蛋

    点击新建仓库 项目名称为自己的昵称 下方提示意思说: 你发现了一个秘密 这是一个特别的仓库 你可以为你的首页增加README.md 就像给项目介绍一样,这是你的自我介绍 点击编辑,里面会与建议模板 以 ...

  7. 零基础如何自学C#?

    前言 本文来源于知乎的一个提问,提问的是一个大一软件工程专业的学生,他想要自学C#但是不知道该怎么去学,这让他感到很迷茫,希望有人能给他一些建议和提供一些学习方向. 个人建议 确认目标:自学C#首先你 ...

  8. python移动文件

    #移动文件(目录) shutil.move("oldpos","newpos") shutil.move("D:/知乎日报/latest/一张优惠券, ...

  9. 基于C#的应用程序单例唯一运行的完美解决方案 - 开源研究系列文章

    今次介绍一个应用程序单例唯一运行方案的代码. 我们知道,有些应用程序在操作系统中需要单例唯一运行,因为程序多开的话会对程序运行效果有影响,最基本的例子就是打印机,只能运行一个实例.这里将笔者单例运行的 ...

  10. [python]爬取手机号码前缀和地区信息

    概述 使用python爬取手机号码前缀7位.区号和地区. 小网站不容易,对爬虫也挺友好,就不放链接了. 代码 import requests from lxml import etree from f ...