代码随想录之链表刷题总结

news2024/12/22 20:27:01

目录

1.链表理论基础

2.移除链表元素

3.设计链表

4.翻转链表

5.两两交换链表中的节点

6.删除链表中的第N个节点

7.链表相交

8.环形链表


1.链表理论基础

链表是一种通过指针串联在一起的线性结构,每一个节点由两部分组成,一个是数据域一个是指针域(存放指向下一个节点的指针),最后一个节点的指针域指向null(空指针的意思)。

链表的入口节点称为链表的头结点也就是head。

如下图所示:

链表的类型

单链表

也就是刚才所说的

双链表

单链表中的指针域只能指向节点的下一个节点。

双链表:每一个节点有两个指针域,一个指向下一个节点,一个指向上一个节点。

双链表 既可以向前查询也可以向后查询。

如图所示:

循环链表

循环链表,顾名思义,就是链表首尾相连。

循环链表可以用来解决约瑟夫环问题。

链表的存储方式

数组是在内存中是连续分布的,但是**链表在内存中不是连续分布**的。

链表是**通过指针域的指针链接在内存中各个节点**

所以链表中的节点在内存中不是连续分布的 ,而是**散乱分布在内存中的某地址上**,分配机制取决于操作系统的内存管理。

如图所示:

这个链表起始节点为2, 终止节点为7,  各个节点分布在内存的不同地址空间上,通过指针串联在一起。

链表的定义

C/C++的定义链表节点方式,如下所示:

struct ListNode {
	int val;//存储节点上面的元素值
	ListNode* next;//用于指向链表的下一个节点,初始时被设置wULL,表示当前节点是链表的末尾
	ListNode(int x) : val(x),next(NULL) {}//构造函数,初始化ListNode的实例,接收一个整型参数x,并将这个值赋给当前节点的val成员,
	//同时将next指针初始化为NULL,表示这个节点后面没有更多的节点

};
/*操作示例*/
ListNode* head = new ListNode(1);//创建链表的头节点,值为1
head->next = new ListNode(2);//在头节点后面添加一个新的节点,值为2

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

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

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

ListNode* head = new ListNode(5);

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

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

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

链表的操作

删除节点

删除D节点,如图所示:

只要将C节点的next指针 指向E节点就可以了。

那有同学说了,D节点不是依然存留在内存里么?只不过是没有在这个链表里而已。

是这样的,所以在C++里最好是再手动释放这个D节点,释放这块内存。

其他语言例如Java、Python,就有自己的内存回收机制,就不用自己手动释放了。

添加节点

如图所示:

可以看出链表的增添和删除都是O(1)操作,也不会影响到其他节点。

但是要注意,要是删除第五个节点,需要从头节点查找到第四个节点通过next指针进行删除操作,查找的时间复杂度是O(n)。

性能分析

把链表的特性和数组的特性进行一个对比,如图所示:

数组在定义的时候,长度就是固定的,如果想改动数组的长度,就需要重新定义一个新的数组。

链表的长度可以是不固定的,并且可以动态增删, 适合数据量不固定,频繁增删,较少查询的场景。

2.移除链表元素

题目:

题意:删除链表中等于给定值 val 的所有节点。

示例 1: 输入:head = [1,2,6,3,4,5,6], val = 6 输出:[1,2,3,4,5]

示例 2: 输入:head = [], val = 1 输出:[]

示例 3: 输入:head = [7,7,7,7], val = 7 输出:[]

思路:

先设置虚拟头节点,因为第一个节点也有可能是val值,然后移除的操作其实就是val值的前一个节点直接跳过val节点,指向val的下一个节点

注意:跳过的节点记得手动释放一下内存,节省空间

代码如下:

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

3.设计链表

题目

a.get(index):获取链表中第 index 个节点的值。如果索引无效,则返回 - 1。
b.addAtHead(val):在链表的第一个元素之前添加一个值为 val 的节点。插入后,新节点将成为链表的第一个节点。
c.addAtTail(val):将值为 val 的节点追加到链表的最后一个元素。
d.addAtIndex(index, val):在链表中的第 index 个节点之前添加值为 val  的节点。
如果 index 等于链表的长度,则该节点将附加到链表的末尾。如果 index 大于链表长度,则不会插入节点。如果index小于0,则在头部插入节点。
e.deleteAtIndex(index):如果索引 index 有效,则删除链表中的第 index 个节点。

注意:

注意初始定义链表的状态

自己在纸上面写一遍

注意index的区间边界,搞清楚链表中的移动大小,以便在正确的位置做插入删除操作

代码如下:

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

    // 初始化链表
    MyLinkedList() {
        _dummyHead = new ListNode(0); // 这里定义的头结点 是一个虚拟头结点,而不是真正的链表头结点
        _size = 0;
    }
    //a.get(index):获取链表中第 index 个节点的值。如果索引无效,则返回 - 1。
    int get(int index) {
        if (index > (_size - 1) || index < 0) {
            return -1;
        }
        else {
            ListNode* cur = _dummyHead->next;
            while (index--) {
                cur = cur->next;
            }
            return cur->next->val;
        }
    }
    //b.addAtHead(val):在链表的第一个元素之前添加一个值为 val 的节点。插入后,新节点将成为链表的第一个节点。
    void addAtHead(int val) {
        ListNode* newNode = new ListNode(val);
        newNode->next = _dummyHead->next;
        _dummyHead->next = newNode;
        _size++;
    }

    //c.addAtTail(val):将值为 val 的节点追加到链表的最后一个元素。
    void addAtTail(int val) {
        ListNode* newNode = new ListNode(val);
        ListNode* cur = _dummyHead;
        while (cur->next != NULL) {
            cur = cur->next;
        }
        newNode->next = cur;

    }
//d.addAtIndex(index, val):在链表中的第 index 个节点之前添加值为 val  的节点。
//如果 index 等于链表的长度,则该节点将附加到链表的末尾。如果 index 大于链表长度,则不会插入节点。如果index小于0,则在头部插入节点。
    void addAtIndex(int index, int val) {
        if (index > _size) return;
        if (index < 0) index = 0;
        ListNode* newNode = new ListNode(val);
        ListNode* cur = _dummyHead;
        while (index--) {
            cur = cur->next;
        }
        newNode->next = cur->next;
        cur->next = newNode;
        _size++;
    }

    //e.deleteAtIndex(index):如果索引 index 有效,则删除链表中的第 index 个节点。
    void deleteAtIndex(int index) {
        ListNode* cur = _dummyHead;
        if (index > _size - 1 || index < 0) {
            return;
        }
        while (index--) {
            cur = cur->next;
        }
        ListNode* temp = cur->next;
        cur->next = cur->next->next;
        delete temp;
        temp = NULL;
        _size--;

    }
    //打印链表
    void printLinkedList() {
        ListNode* cur = _dummyHead;
        while (cur->next != NULL) {
            cout << "cur->next-val = " << cur->next->val << endl;
            cur = cur->next;
        }
        cout << endl;
    }
public:
    ListNode* _dummyHead;
    int _size;
};

4.翻转链表

题目:

题意:反转一个单链表(是将箭头翻转,不是里面的元素进行翻转)

示例: 输入: 1->2->3->4->5->NULL 输出: 5->4->3->2->1->NULL

思路:

设置双指针法,一个pre先指向NULL,然后cur在head节点,不断更新指向

注意:

使用temp先保存cur->next,因为指向改变了,不存储的话无法继续进行

代码如下:

class Solution {
public:
	ListNode* reverseList(ListNode* head) {
		ListNode* pre = NULL;
		ListNode* cur = head;
		ListNode* temp = new ListNode(0);
		while (cur) {
			temp = cur->next;
			cur->next = pre;
			//更新pre和cur
			pre = cur;
			cur = temp;
		}
		return pre;

	}
};

5.两两交换链表中的节点

题目:

给定一个链表,两两交换其中相邻的节点,并返回交换后的链表。

你不能只是单纯的改变节点内部的值,而是需要实际的进行节点交换。

思路:

按照下图中的三部进行操作即可

注意:

记得保存cur->next与cur->next->next->next的值,因为指向发生了改变

代码:

class Solution {
public:
	ListNode* swapPairs(ListNode* head) {
		ListNode* dummyhead = new ListNode(0);
		dummyhead->next = head;
		ListNode* cur = dummyhead;
		while (cur->next != nullptr && cur->next->next != nullptr) {
			ListNode* temp = cur->next;
			ListNode* temp1 = cur->next->next->next;
			/*dummyhead->next = temp1;
			temp1->next = temp;
			temp = cur->next->next->next;*///错误写法,不可取
			cur->next = cur->next->next;
			cur->next->next = temp;
			cur->next->next->next = temp1;

			cur = cur->next->next;
		}
		ListNode* result = dummyhead->next;
		delete dummyhead;
		return result;
	}
};

6.删除链表中的第N个节点

题目:

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

输入:head = [1,2,3,4,5], n = 2 输出:[1,2,3,5]

示例 2:

输入:head = [1], n = 1 输出:[]

示例 3:

输入:head = [1,2], n = 1 输出:[1]

思路:

使用双指针法进行解决,先定义fast指针和slow指针,初始化为虚拟头节点,fast先走n步,然后俩指针一起开始移动,直到fast变为NULL停止,此时slow指向的正好是删除节点的前一个节点,这是再改变节点指向即可

注意:

slow一定要在删除节点的前一个,不然无法继续操作

对于while循环中的逻辑要充足考虑,不要漏掉情况

代码如下:

class Solution {
public:
	ListNode* removeNthFromEnd(ListNode* head, int n) {
		ListNode* dummyhead = new ListNode(0);
		dummyhead->next = head;
		ListNode* slow = dummyhead;
		ListNode* fast = dummyhead;
		while (n--&&fast->next!=nullptr) {
			fast = fast->next;
		}
		while (fast->next != nullptr) {
			slow = slow->next;
			fast = fast->next;
		}
		slow->next = slow->next->next;
		return dummyhead->next;
	}
};

7.链表相交

题目:

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

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

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

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

思路:

此时一定要充分理解链表相交,:若两个链表相交,则两个链表有共同的节点,从这个节点之后,后面的节点都会重叠,直到链表结束,若相交,则两个链表呈现Y字型

 先计算两个列表的长度差值,让curA和curB这两个指针对齐,然后再移动,判断指针是否相等

如下图:

注意:

明确链表相交是什么

判断的是指针,不是数值

代码:

class Solution {
	ListNode* listjiao(ListNode* headA, ListNode* headB) {
		ListNode* curA = headA;
		ListNode* curB = headB;
		int sizeA = 0;
		int sizeB = 0;

		while (curA != nullptr) {
			sizeA += 1;
			curA = curA->next;
		}

		while (curB != nullptr) {
			sizeB += 1;
			curB = curB->next;
		}

		if (sizeB > sizeA) {
			swap(sizeA, sizeB);
			swap(headA, headB);
		}

		int gap = sizeA - sizeB;
		while (gap--) {
			curA = curA->next;
		}

		while (curA != nullptr) {
			if (curA == curB) {
				return curA;
			}
			else {
				curA = curA->next;
				curB = curB->next;
			}
		}
		return NULL;
	}
};

8.环形链表

题目:

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

为了表示给定链表中的环,使用整数 pos 来表示链表尾连接到链表中的位置(索引从 0 开始)。 如果 pos 是 -1,则在该链表中没有环。

说明:不允许修改给定的链表。

思路:

判断1:链表是否有环
快慢指针法,从头节点出发,fast指针每次移动两个节点,slow指针每次移动一个节点,若相遇就是有环。
判断2:环的入口节点
分别从头节点以及相遇节点出发一个指针,每次只走一个,相遇的时候就是入口节点

注意:

最后返回的是环形入口节点

代码:

class Solution {
public:
	ListNode* detecCycle(ListNode* head) {
		ListNode* fast = head;
		ListNode* slow = head;
		//while (fast->next->next != nullptr && slow != nullptr) {//啰嗦了,可以改一下
		while(fast!=NULL&&fast->next!=NULL) {
			fast = fast->next->next;
			slow = slow->next;
			//快慢指针相遇
			if (fast == slow) {
				ListNode* index1 = head;
				ListNode* index2 = fast;
				while (index1 != index2) {
					index1 = index1->next;
					index2 = index2->next;
				}
				return index1;
			}
		}
		return nullptr;
	}
};

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

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

相关文章

Notepad++ 插件安装,The plugin package is not found问题

问题&#xff1a; 今天想用自己电脑的Notepad来分析一下几个json文件&#xff0c;后续工作传输都使用json通信&#xff0c;公司装了jsonView插件都没什么问题。自己电脑装了就问题百出&#xff1a; 本人版本&#xff1a; 揣测1&#xff1a; 是不是管理员权限的问题&#xff0c;…

【操作系统】每日 3 题(三)

✍个人博客&#xff1a;https://blog.csdn.net/Newin2020?typeblog &#x1f4e3;专栏地址&#xff1a;https://blog.csdn.net/newin2020/category_12820365.html &#x1f4da;专栏简介&#xff1a;在这个专栏中&#xff0c;我将会分享 C 面试中常见的面试题给大家~ ❤️如果…

【万兴科技-注册_登录安全分析报告】

前言 由于网站注册入口容易被黑客攻击&#xff0c;存在如下安全问题&#xff1a; 暴力破解密码&#xff0c;造成用户信息泄露短信盗刷的安全问题&#xff0c;影响业务及导致用户投诉带来经济损失&#xff0c;尤其是后付费客户&#xff0c;风险巨大&#xff0c;造成亏损无底洞…

duilib 进阶 之 TileListBox 列表

目录 一、TileListBox 1、样式 1)、整体列表分列设置 2)、列表项样式设置 3)、选中后出现√号,horver时 出现边框色 的实例 2、代码 1)、普通动态添加列表项 2)、列表项样式中有自定义控件时 3)、获得选中项 一、TileListBox Tile [taɪl] ,瓦片 棋子 Ti…

专线物流公共服务平台:数据驱动,标准引领,共创金融双赢新时代

专线物流公共服务平台&#xff1a;数据驱动&#xff0c;标准引领&#xff0c;共创金融双赢新时代 在当今这个数据驱动、标准引领、金融赋能的经济发展新时代&#xff0c;专线物流作为商贸流通领域的重要一环&#xff0c;正面临着前所未有的机遇与挑战。为应对复杂多变的市场环…

日本Harmonic行星减速机HPG系列 薄壁弹性齿轮技术实现低背隙控制

科技飞速发展&#xff0c;工业领域对于设备的精度和刚性要求越来越高。日本Harmonic Drive Systems 公司凭借其在精密传动领域的深厚积累与不断创新&#xff0c;成功开发出一款具有高精度、高刚性的伺服电机用行星减速机 ——HPG系列&#xff0c;为众多行业带来了全新的精密传动…

win10系统cad2007安装提示缺少net framework 3.5安装错误怎么修复

浏览器地址栏输入www.dnz9.com远程解决netframework问题 由于AutoCAD 2007是一款比较老的软件&#xff0c;它可能与最新的Windows操作系统存在兼容性问题。所以我们在安装的cad2007的时候会提示“未安装net缺少该组件时不能安装”。在Windows 10上安装AutoCAD 2007时遇到缺少.N…

Flash的语音ic型号有哪些?

深圳唯创知音电子有限公司在语音技术领域具有深厚的积累&#xff0c;其Flash语音IC产品凭借高性能和广泛的应用领域&#xff0c;在市场上占据了一席之地。以下是对该公司Flash语音IC产品的详细介绍&#xff1a; 一、产品概述 Flash语音IC是一种采用Flash存储技术的语音芯片&…

我在命令行下学日语

同一个动作重复 300 遍&#xff0c;肌肉就会有记忆&#xff0c;重复 600 遍&#xff0c;脊柱就会有记忆&#xff0c;学完五十音图不熟练&#xff0c;经常遗忘或者要好几秒才想得起来一个怎么办&#xff1f;没关系&#xff0c;我做了个命令行下的小游戏 KanaQuiz 来帮助你记忆&a…

【GESP】C++三级练习BCQM3091,选择题判定

GESP三级字符串string和一级知识点if-else分支语句练习&#xff0c;非常基础&#xff0c;对于我孩子来说练习重点在一级部分&#xff0c;字符串只是碰巧遇到了。 题目题解详见&#xff1a;https://www.coderli.com/gesp-3-bcqm3091/ 【GESP】C三级练习BCQM3091&#xff0c;选…

Vue前端开发:事件绑定方式

事件定义 在Vue中&#xff0c;当一个元素通过使用v-on或语法糖指令绑定某个事件后&#xff0c;则完成了事件被定义的过程&#xff0c;在这定义的过程中&#xff0c;指令的后面是定义事件的名称&#xff0c;等号的后面是事件被触发后执行的函数&#xff0c;当然&#xff0c;也可…

PHP + Windows小皮面板 + VScode 安装教程

目录 1. 小皮面板安装包 下载 2、配置MySQL 可以在cmd命令框中使用 3. VScode安装 如有错误&#xff0c;烦请批评指正 1. 小皮面板安装包 下载 官方地址https://old.xp.cn/download.html 下载完后&#xff0c;一路next&#xff0c;文件路径自定义 2、配置MySQL 可以在cm…

【小白学机器学习29】 概率统计与图形 ( hist, bar, pie , box ,scatter ,line)

目录 1 频度/次数 1.1 频度统计表&#xff1a;频度分布表 1.2 频数分布图直方图 histogram / hist 1.3 对比&#xff0c;柱状图 bar graph /column chart 2 饼图 pie chart 2.1饼图特点 3 南丁格尔玫瑰图 4 茎叶图 stem-and-leaf display 5 箱型图 box plot 6 …

ssm基于web的素材网的设计与实现+vue

系统包含&#xff1a;源码论文 所用技术&#xff1a;SpringBootVueSSMMybatisMysql 免费提供给大家参考或者学习&#xff0c;获取源码请私聊我 需要定制请私聊 目 录 摘要 I Abstract II 1绪论 1 1.1研究背景与意义 1 1.1.1研究背景 1 1.1.2研究意义 1 1.2国内外研究…

QT 跨平台优势独特,效果实例设计精彩呈现

QT 的跨平台优势确实独特而显著。它能够在不同的操作系统上实现一致的用户体验&#xff0c;无论是 Windows、Linux 还是 macOS。在效果实例设计中&#xff0c;QT 可以展现出精美的界面和流畅的交互。比如&#xff0c;一个基于 QT 开发的图形设计软件&#xff0c;在各个平台上都…

GXYCTF2019:gakki

把题目给的附件解压后给了张图片&#xff0c;顺带着瞟一眼属性&#xff0c;没有值得注意的 binwalk检测一手&#xff0c;看见有个rar压缩包 提取出来的压缩包是有密码的&#xff0c;但是题目并没有给出获取密码的途径&#xff0c;所以先爆破试试&#xff0c;用最常用的四位数爆…

从0开始搭建一个生产级SpringBoot2.0.X项目(六)RestTemplate调用第三方接口

前言 最近有个想法想整理一个内容比较完整springboot项目初始化Demo。 SpringBoot使用RestTemplate由服务端向外发起网络请求 一、将RestTemplate配置初始化为一个Bean 修改RestTemplate默认的客户端&#xff0c;例如将其改成HttpClient客户端 package com.murg.bootdemo.…

Cyber​​Panel filemanager/upload 远程命令执行漏洞复现

0x01 产品简介 CyberPanel是一个开源的Web控制面板,它提供了一个用户友好的界面,用于管理网站、电子邮件、数据库、FTP账户等。CyberPanel旨在简化网站管理任务,使非技术用户也能轻松管理自己的在线资源。 0x02 漏洞概述 该漏洞源于filemanager/upload接口未做身份验证和…

Qt开发————网络编程

目录 Socket套接字 IP地址 端口号 IP地址与端口号的组合 MAC地址的特征 MAC地址的作用 重要性 例子 TCP/UDP协议 TCP UDP 网络编程1.0-----网络与通信介绍_计算机网络与通信网络csdn-CSDN博客 Socket套接字 IP地址 IP地址&#xff08;Internet Protocol Address&…

Spring Cloud Sleuth(Micrometer Tracing +Zipkin)

分布式链路追踪 分布式链路追踪技术要解决的问题&#xff0c;分布式链路追踪&#xff08;Distributed Tracing&#xff09;&#xff0c;就是将一次分布式请求还原成调用链路&#xff0c;进行日志记录&#xff0c;性能监控并将一次分布式请求的调用情况集中展示。比如各个服务节…