一刷代码随想录——链表

news2024/11/16 5:39:39

1.理论基础

链表节点的定义:

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) {}
};

根据卡哥提示,由于力扣中已经给出如上节点定义,所以平时刷题时确实可能会忽略这部分。下面引用卡哥关于此话题的原文(感谢卡哥):

“有同学说了,我不定义构造函数行不行,答案是可以的,C++默认生成一个构造函数。

但是这个构造函数不会初始化任何成员变量,下面我来举两个例子:

通过自己定义构造函数初始化节点:

ListNode* head = new ListNode(5);

使用默认构造函数初始化节点:

ListNode* head = new ListNode();
head->val = 5;

所以如果不定义构造函数使用默认构造函数的话,在初始化的时候就不能直接给变量赋值!”

2 力扣203.移除链表元素

题目描述:

给你一个链表的头节点 head 和一个整数 val ,请你删除链表中所有满足 Node.val == val 的节点,并返回 新的头节点

实际头结点:

class Solution {
public:
    ListNode* removeElements(ListNode* head, int val) {
    //剪枝,由Case:7、7、7、7而来,融合了head->null链
        while (head && head->val == val) {
            ListNode* tmp = head;
            head = head->next;
            delete tmp;
        }
        if (!head) return head;

        ListNode* p = head;
        while (p->next) {
            if (p->next->val != val) p = p->next;
            else {
                ListNode* tmp = p->next;
                p->next = p->next->next;
                delete tmp;
            }
        }
        return head;
    }
};

虚拟头结点:

class Solution {
public:
    ListNode* removeElements(ListNode* head, int val) {
        ListNode* dummyhead = new ListNode(0);
        dummyhead->next = head;
        ListNode* p = dummyhead;
        while (p->next) {
            if (p->next->val != val)p = p->next;
            else {
                ListNode* tmp = p->next;
                p->next = p->next->next;
                delete tmp;
            }
        }
        head = dummyhead->next;
        delete dummyhead;
        return head;
    }
};

3 力扣707.设计链表

题目描述:

class MyLinkedList {
public:
    struct LinkedNode {
        int val;
        LinkedNode* next;
        LinkedNode(int val):val(val), next(nullptr){}
    };

    MyLinkedList() {
        _dummyHead = new LinkedNode(0);
        _size = 0;
    }

    int get(int index) {
        if (index > (_size - 1) || index < 0) {
            return -1;
        }
        LinkedNode* cur = _dummyHead->next;
        while(index--){
            cur = cur->next;
        }
        return cur->val;
    }

    void addAtHead(int val) {
        LinkedNode* newNode = new LinkedNode(val);
        newNode->next = _dummyHead->next;
        _dummyHead->next = newNode;
        _size++;
    }

    void addAtTail(int val) {
        LinkedNode* newNode = new LinkedNode(val);
        LinkedNode* cur = _dummyHead;
        while(cur->next != nullptr){
            cur = cur->next;
        }
        cur->next = newNode;
        _size++;
    }

    void addAtIndex(int index, int val) {
        if (index > _size) {
            return;
        }
        LinkedNode* newNode = new LinkedNode(val);
        LinkedNode* cur = _dummyHead;
        while(index--) {
            cur = cur->next;
        }
        newNode->next = cur->next;
        cur->next = newNode;
        _size++;
    }

    void deleteAtIndex(int index) {
        if (index >= _size || index < 0) {
            return;
        }
        LinkedNode* cur = _dummyHead;
        while(index--) {
            cur = cur ->next;
        }
        LinkedNode* tmp = cur->next;
        cur->next = cur->next->next;
        delete tmp;
        _size--;
    }

private:
    int _size;
    LinkedNode* _dummyHead;

};

4 力扣206.反转链表

题目描述:

三指针

尾节点指向nullptr不可省略

class Solution {
public:
    ListNode* reverseList(ListNode* head) {
        if (!head || !head->next) return head;
        ListNode* p = head;
        if (!head->next->next) {
            head = head->next;
            head->next = p;
            p->next = nullptr;
            return head;
        }
        
        ListNode* q = p->next;
        ListNode* r = q->next;
        p->next = nullptr;
        while (r) {
            q->next = p;
            p = q;
            q = r;
            r = r->next;
        }
        q->next = p;
        head = q;
        return head;
    }
};

正向递归:

class Solution {
public:
    ListNode* reverse(ListNode* pre,ListNode* cur){
        if(cur == NULL) return pre;
        ListNode* temp = cur->next;
        cur->next = pre;
            // 可以和双指针法的代码进行对比,如下递归的写法,其实就是做了这两步
            // pre = cur;
            // cur = temp;
        return reverse(cur,temp);
    }
    ListNode* reverseList(ListNode* head) {
            // 和双指针法初始化是一样的逻辑
            // ListNode* cur = head;
            // ListNode* pre = NULL;
        return reverse(NULL, head);
    }
};

反向递归:

class Solution {
public:
    ListNode* reverseList(ListNode* head) {
        // 边缘条件判断
        if(head == NULL) return NULL;
        if (head->next == NULL) return head;
        
        // 递归调用,翻转第二个节点开始往后的链表
        ListNode *last = reverseList(head->next);
        // 翻转头节点与第二个节点的指向
        head->next->next = head;
        // 此时的 head 节点为尾节点,next 需要指向 NULL
        head->next = NULL;
        return last;
    }
}; 

5 力扣19.删除链表的倒数第N个节点

题目描述:

给你一个链表,删除链表的倒数第 n 个结点,并且返回链表的头结点。

双指针:

class Solution {
public:
    ListNode* removeNthFromEnd(ListNode* head, int n) {
        ListNode* dummyhead = new ListNode(0);
        dummyhead->next = head;
        ListNode* p = dummyhead;
        ListNode* q = head;
        while (n--)q = q->next;
        if (!q) {
            ListNode* tmp = head;
            head = head->next;
            delete tmp;
            return head;
        }
        while (q) {
            p = p->next;
            q = q->next;
        }
        ListNode* tmp = p->next;
        p->next = p->next->next;
        delete tmp;
        return head;
    }
};

6 力扣142.环形链表II

题目描述:

给定一个链表的头节点 head ,返回链表开始入环的第一个节点。 如果链表无环,则返回 null。

如果链表中有某个节点,可以通过连续跟踪 next 指针再次到达,则链表中存在环。 为了表示给定链表中的环,评测系统内部使用整数 pos 来表示链表尾连接到链表中的位置(索引从 0 开始)。如果 pos 是 -1,则在该链表中没有环。注意:pos 不作为参数进行传递,仅仅是为了标识链表的实际情况。

不允许修改 链表。

class Solution {
public:
    ListNode* detectCycle(ListNode* head) {
        ListNode* p = head;
        ListNode* s = head;
        ListNode* f = head;
        if (!head || !head->next) return NULL;
        do {
            s = s->next;
            f = f->next->next;
        } while (s != f && f && f->next);
        if (!f || !f->next) return NULL;
        while (s != p) {
            s = s->next;
            p = p->next;
        }
        return p;
    }
};

本题比较有趣的是采用步长为2的快指针f和步长为1的慢指针s会相遇在环中一个节点,这个节点到环的入口的节点数等于head到环的入口的节点数。然后再从相遇点派出一个速度为1 的指针(s即可),同时,从head也派出一个p,它们就会在环的入口相遇。

7 力扣24. 两两交换链表中的节点

题目描述:

给你一个链表,两两交换其中相邻的节点,并返回交换后链表的头节点。你必须在不修改节点内部的值的情况下完成本题(即,只能进行节点交换)。

四指针:

s作为上一对尾,p和q作为交换对,r作为下一对头

class Solution {
public:
    ListNode* swapPairs(ListNode* head) {
        ListNode* p = head;
        if (!head || !head->next) return head;
        ListNode* q = head->next;
        ListNode* r = head->next->next;
        q->next = p;
        p->next = r;
        head = q;        
        while (r && r->next) {
            ListNode* s = p;
            p = p->next;
            q = r->next;
            r = r->next->next;
            q->next = p;
            p->next = r;
            s->next = q;
        }
        return head;
    }
};

8 力扣面试题 02.07. 链表相交

题目描述:

给你两个单链表的头节点 headA 和 headB ,请你找出并返回两个单链表相交的起始节点。如果两个链表没有交点,返回 null 。

图示两个链表在节点 c1 开始相交:

题目数据 保证 整个链式结构中不存在环。

注意,函数返回结果后,链表必须 保持其原始结构

class Solution {
public:
    ListNode* getIntersectionNode(ListNode* headA, ListNode* headB) {
        ListNode* p = headA;
        ListNode* q = headB;
        int cntA = 0, cntB = 0;
        while (p) {
            p = p->next;
            cntA++;
        }
        while (q) {
            q = q->next;
            cntB++;
        }
        delete p, q;
        ListNode* a = headA;
        ListNode* b = headB;
        int d = cntA > cntB ? (cntA - cntB) : (cntB - cntA);
        if (cntA > cntB) while (d--) a = a->next;    
        else while (d--) b = b->next;        
        while (a != b) {
            a = a->next;
            b = b->next;
        }
        return a;
    }
};

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/184840.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

C++中拷贝构造函数、拷贝赋值运算符、析构函数、移动构造函数、移动赋值运算符(三/五法则)

1、介绍 三五法则是针对C中类的成员和类对象的操作函数。 三法则是指&#xff1a;拷贝构造函数、拷贝赋值运算符、析构函数。 五法则是在三法则的基础上增加了&#xff1a;移动构造函数、移动赋值运算符。 2、拷贝构造函数 定义&#xff1a;如果构造函数的第一个参数是自身…

Postman前置脚本

位置&#xff1a;作用&#xff1a;调用脚本之前需要执行的代码片段一、产生随机数字生成0-1之间的随机数&#xff0c;包括0&#xff0c;不包括1&#xff1b;var random Math.random();console.log("随机数",random);获取最小值到最大值之前的整数随机数function Get…

2019-ICML-Graph U-Nets

2019-ICML-Graph U-Nets Paper: https://arxiv.org/abs/1905.05178 Code: https://github.com/HongyangGao/Graph-U-Nets 图U-Nets 作者将CNN上的U-Net运用到了图分类上&#xff0c;因为我们主题是图分类&#xff0c;就不对U-Net进行论述了&#xff0c;只对其中的gPool&#…

eureka 读写锁的一点思考

读写锁 读写锁一般实现 读读不互斥 读写互斥 写写互斥 读写锁的好处是&#xff0c;面对读多写多的场景会拥有比较好的表现 一般我们会在读操作加上读锁&#xff0c;写操作加上写锁。但是最近我发现eureka 在使用读写锁的时候是相反的&#xff0c; 也就是说在读操作加上了读锁&…

2023最值得入手的运动耳机是哪款、口碑最好的运动蓝牙耳机推荐

不知道有没有和我一样的小伙伴&#xff0c;在运动时特别喜欢听音乐&#xff0c;每次听到一首合适的音乐&#xff0c;感觉运动起来都更有激情和活力了。所以这时候就需要挑选一款舒适的耳机了。别看市面上各种各样的运动耳机很多&#xff0c;但实际上能真正适合运动的少之又少&a…

oss服务端签名后直传分析与代码实现

文章目录1.简介1.1 普通上传方式1.2 服务端签名后直传3.服务端签名后直传文档3.1 用户向应用服务器请求上传Policy和回调。3.2 应用服务器返回上传Policy和签名给用户。3.3 用户使用Post方法向OSS发送文件上传请求。4.实战开发-后端4.1 pom.xml核心配置4.2 application.yml核心…

Java两大工具库:Commons和Guava(2)

您好&#xff0c;我是湘王&#xff0c;这是我的CSDN博客。值此新春佳节&#xff0c;我给您拜年啦&#xff5e;祝您在新的一年中所求皆所愿&#xff0c;所行皆坦途&#xff0c;展宏“兔”&#xff0c;有钱“兔”&#xff0c;多喜乐&#xff0c;常安宁&#xff01;开发中有一类应…

如何在es中查询null值

文章目录1、背景2、需求3、准备数据3.1 创建mapping3.2 插入数据4、查询 name字段为null的数据5、查询address不存在或值直接为null的数据6、参考链接1、背景 在我们向es中写入数据时&#xff0c;有些时候数据写入到es中的是null&#xff0c;或者没有写入这个字段&#xff0c;…

离散数学与组合数学-08谓词逻辑

文章目录离散数学与组合数学-08谓词逻辑8.1 谓词的引入8.1.1 引入谓词逻辑8.1.2 个体词与谓词8.2 量词的引入8.2.1 量词引入8.2.2 个体域符号化8.2.3 量词真值确定8.3 谓词符号化举例8.3.1 示例一8.3.2 示例二8.3.3 示例三8.3.4 示例四8.4 谓词合式公式8.4.1 四类符号8.4.2 项8…

MySQL运维(一)MySQL中的日志、Mysql主从复制

MySQL运维(一)MySQL中的日志、Mysql主从复制 1、MySQL日志 1.1 错误日志 错误日志是 MySQL 中最重要的日志之一&#xff0c;它记录了当 mysqld 启动和停止时&#xff0c;以及服务器在运行过程中发生任何严重错误时的相关信息。当数据库出现任何故障导致无法正常使用时&#…

Elasticsearch 需要了解的都在这

ES选主过程&#xff1f;其实ES的选主过程其实没有很高深的算法加持&#xff0c;启动过程中对接点的ID进行排序&#xff0c;取ID最大节点作为Master节点&#xff0c;那么如果选出来的主节点中存储的元信息不是最新的怎么办&#xff1f;其实他是分了2个步骤做这件事&#xff0c;先…

react 项目 中使用 Dllplugin 打包优化技巧

目录 0.React和DLLPlugin 前言 使用步骤 结果截图 主要说明 0.React和DLLPlugin React 是一个用于构建用户界面的 JavaScript 库。它由 Facebook 开发&#xff0c;现在由 Facebook 和一个由个人开发者和公司组成的社区维护。React 允许开发人员构建可重用的 UI 组件并有…

“回文子串、最长回文子序列”总结,动态规划再显神通(Java实现)

目录 一、回文子串 1.1、dp定义 1.2、递推公式 1.3、初始化 1.4、遍历顺序 1.5、解题代码 二、最长回文子序列 2.1、dp定义 2.2、递推公式 2.3、初始化 2.4、遍历顺序 2.5、解题代码 一、回文子串 题目描述&#xff1a; 题目来源&#xff1a;647. 回文子串 1.1、dp定…

解决使用copy.deepcopy()拷贝Tensor或model时报错只支持用户显式创建的Tensor问题

模型训练过程中常需边训练边做validation或在训练完的模型需要做测试&#xff0c;通常的做法当然是先创建model实例然后掉用load_state_dict()装载训练出来的权重到model里再调用model.eval()把模型转为测试模式&#xff0c;这样写对于训练完专门做测试时当然是比较合适的&…

ssm学生心理健康测评网的规划与设计

摘 要 1 Abstract 1 1 绪论 1 1.1 课题背景 1 1.2 课题研究现状 1 1.3 初步设计方法与实施方案 2 1.4 本文研究内容 2 2 系统开发环境 4 2.1 JSP技术介绍 4 2.2 B/S模式 4 2.3 MySQL环境配置 5 3 系统分析 6 3.1 系统可行性分析 6 3.1.…

【模糊神经网络】基于模糊神经网络的倒立摆轨迹跟踪控制

临近春节没啥事做&#xff0c;突然想起前两年未完成的模糊神经网络&#xff0c;当时是学了一段时间&#xff0c;但是到最后矩阵求偏导那块始终不对&#xff0c;最后也不了了之了&#xff0c;趁最近有空&#xff0c;想重新回顾回顾&#xff0c;看看会不会产生新的想法。经过不断…

elasticsearch基本操作

elasticsearch基本操作基础两种模式:ik分词器词库拓展索引库操作mapping映射属性typeindexanalyzerproperties索引库的CRUD创建修改查询删除文档操作创建查询修改删除基础 本教程使用es8.6.0与kibana作为测试环境 打开开发工具 ## 1.查看节点信息 GET /_cat/nodes?v ## 2.查…

【JUC并发编程】深入浅出Java并发基石——AQS

【JUC并发编程】深入浅出Java并发基石——AQS 参考资料&#xff1a; RedSpider社区——第十一章 AQS 深入剖析并发之AQS独占锁 1.5w字&#xff0c;30图带你彻底掌握 AQS&#xff01; 深入浅出AbstractQueuedSynchronizer 我画了35张图就是为了让你深入 AQS 动画演示AQS的核心原…

遍历 “可变参数模板” 的模板参数

类模板和函数模板&#xff0c;只能包含固定数量的模板参数&#xff0c;C11支持模板参数可变&#xff0c;那么在不知道模板参数有多少个的情况下&#xff0c;如何遍历模板参数&#xff1f; 目录 一、可变参数模板的声明 二、可变参数模板的遍历 1、递归遍历 2、非递归遍历 …

idea使用DataBase连接数据库 Free MyBatis Tool自动生成 实体类工具使用

DataBase DataBase连接数据库 设置DataSources Host 》IP地址Port 》端口号User 》用户名Password 》密码Database 》连接的数据库 设置驱动 Drives tables 文件夹中即所连接数据库中表 Free MyBatis Tool自动生成 实体类&#xff0c;Mapper &#xff0c;以及mapper.xml 选…