【数据结构与算法】03 链表(基础知识+面试高频leetcode题目)
目录
数组&链表基础
高频面试题(leetcode)
206 反转链表(常考)
方法1:迭代算法(双指针)(cpp&python)
方法2:递归解法
妖魔化的双指针算法。
24 两两交换链表中的节点
拓展:哑节点
141环形链表
方法1:快慢指针算法。
方法2:哈希表
142 环形链表2
扩展:哈希表基础及其在c++和python中的基本语法。
set和unordered_set区别以及适用情况
致谢
数组&链表基础
数组定义:
数组是一个固定长度的存储相同数据类型的数据结构,数组中的元素被存储在一段连续的内存空间中。它是最简单的数据结构之一,大多数现代编程语言都内置数组支持。
数组在遍历时速度非常快,但是在删除和增加元素时需要平移大量的元素(删除和增加首末位置除外),复杂度为o(n)。
数组特点:
- 使用前需要申请数组长度,声明长度之后不能更改;
- 插入和删除操作需要移动大量的元素,效率比较慢;
- 只能存储一种类型的数据;
链表定义:
链表是一种物理存储单元上非联系、非顺序的存储结构。数据元素中的逻辑顺序是通过链表中的指针连接次序依次实现的,链表由一系列的节点(链表中每一个元素称为节点)组成,节点可以在运行时动态生成,节点的数据空间一般会包含一个数据域和一个指针域,该指针一般称为next,用来指向下一个节点的位置。
链表特点:
- 节点之间通过指针相连;
- 每个节点有一个前驱节点和一个后继节点;
- 首节点没有前驱节点,尾节点没有后继节点;
- n个节点离散分配;
链表图解
链表分类:
单向链表:
链表中的元素只能指向链表中的下一个元素,元素之间不能互相指向。
双向链表:
每个链表既有指向下一个元素的指针,又有指向上一个元素的指针,每个节点都有两个指针。
循环链表:
高频面试题(leetcode)
206 反转链表(常考)
206. 反转链表 - 力扣(LeetCode) (leetcode-cn.com)https://leetcode-cn.com/problems/reverse-linked-list/
方法1:迭代算法(双指针)(cpp&python)
- 定义curr,pre指针,curr指针初始化为head,pre指针为空指针;
- 定义tmp指针,存储curr的下一节点;
- curr的next指针指向pre;
- curr和pre均向前移动一个位置;
/*** 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*curr = head,*pre = nullptr; //定义两个指针while(cur){ListNode* tmp = cur->next; // 存储当前的下一个节点数据curr->next = pre; //cur下一节点 指向prepre = curr; //pre指针前进一位curr = tmp; // cur指针前进一位}return pre; }
};
# Definition for singly-linked list.
# class ListNode:
# def __init__(self, val=0, next=None):
# self.val = val
# self.next = next
class Solution:def reverseList(self, head: ListNode) -> ListNode:cur,pre = head,Nonewhile cur:# 同时赋值,省掉tmpcur.next,pre,cur = pre,cur,cur.nextreturn pre
方法2:递归解法
双指针的办法是调换相邻的两个节点,递归是找到链表的最后一个节点,从尾到首依次反转。
/*** 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 == 0 || head->next == 0) return head;ListNode* tmp = reverseList(head->next);head->next->next = head;head->next = nullptr;return tmp;}
};
# Definition for singly-linked list.
# class ListNode:
# def __init__(self, val=0, next=None):
# self.val = val
# self.next = next
class Solution:def reverseList(self, head: ListNode) -> ListNode:
# if head is None or head.next is None:return head # 这个也行if not head or not head.next:return headtmp = self.reverseList(head.next)head.next.next = headhead.next = Nonereturn tmp
妖魔化的双指针算法。
- 定义指针curr,初始化为head;
- 将head的下一个节点的next指向curr,实现局部反转;
- 局部反转完成之后,curr和head的next指针同时向前移动一个位置;
- 循环,一直到curr达到链表的最后一个节点;
/*** 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) { return nullptr;}ListNode* curr = head;while (head->next){ListNode* tmp = head->next->next;head->next->next= curr;curr = head->next;head->next = tmp;}return curr; }
};
# Definition for singly-linked list.
# class ListNode:
# def __init__(self, val=0, next=None):
# self.val = val
# self.next = next
class Solution:def reverseList(self, head: ListNode) -> ListNode:if head == None:return Nonecurr = headwhile (head.next):tmp = head.next.nexthead.next.next = currcurr = head.nexthead.next = tmpreturn curr
24 两两交换链表中的节点
迭代算法,创建哑节点。
- 创建哑结点,令dummyHead.next = head;tmp表示当前到达的节点,初始化为dummyHead;每次交换tmp后面的两个节点。
- tmp后面的节点分别为node1和node2,交换之前:tmp->node1->node2,交换之后:tmp->node2->node1;
- 迭代,当新的链表的头节点为dummyHead.next,停止迭代。
示意图:
/*** 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* swapPairs(ListNode* head) {ListNode* dummyHead = new ListNode(0);dummyHead->next = head;ListNode* tmp = dummyHead;while (tmp->next != nullptr && tmp->next->next != nullptr){ListNode* node1 = tmp->next;ListNode* node2 = tmp->next->next;tmp->next = node2;node1->next = node2->next;node2->next = node1;tmp = node1; }return dummyHead->next;}
};
# Definition for singly-linked list.
# class ListNode:
# def __init__(self, val=0, next=None):
# self.val = val
# self.next = next
class Solution:def swapPairs(self, head: ListNode) -> ListNode:dummyHead = ListNode(0)dummyHead.next = headtmp = dummyHeadwhile (tmp.next and tmp.next.next):node1 = tmp.nextnode2 = tmp.next.nexttmp.next = node2node1.next = node2.nextnode2.next = node1tmp = node1return dummyHead.next
拓展:哑节点
哑节点是在处理与链表相关的操作时,设置在链表头之前的指向链表头的节点,用于简化与链表头相关的操作。因为LeetCode上的题的测试用例都是在头结点就已经存储数据,所以我们需要一个哑结点,放在头结点的前面。
ListNode dummy = new ListNode(0);
dummy.next = head;
//head是链表的头节点,dummy就是指向链表头部的哑节点。
具体可以参考:
(15条消息) 链表 - 哑节点_Hi-YOLO的博客-CSDN博客_哑节点
141环形链表
141. 环形链表 - 力扣(LeetCode) (leetcode-cn.com)https://leetcode-cn.com/problems/linked-list-cycle/
方法1:快慢指针算法。
我们定义两个指针,一快一满。慢指针每次只移动一步,而快指针每次移动两步。初始时,慢指针在位置 head,而快指针在位置 head.next。这样一来,如果在移动的过程中,快指针反过来追上慢指针,就说明该链表为环形链表。否则快指针将到达链表尾部,该链表不为环形链表。
步骤示意图:
/*** Definition for singly-linked list.* struct ListNode {* int val;* ListNode *next;* ListNode(int x) : val(x), next(NULL) {}* };*/
class Solution {
public:bool hasCycle(ListNode *head) {if (head == nullptr || head->next == nullptr){ return false;}ListNode* fast = head->next;ListNode* slow = head;while (fast != slow){if (fast == nullptr || fast->next == nullptr){ return false;}fast = fast->next->next;slow = slow->next;}return true; }
};
# Definition for singly-linked list.
# class ListNode:
# def __init__(self, x):
# self.val = x
# self.next = Noneclass Solution:def hasCycle(self, head: Optional[ListNode]) -> bool:if(head == None or head.next == None):return Falsefast = head.nextslow = headwhile (fast != slow):if (fast == None or fast.next == None):return Falsefast = fast.next.nextslow = slow.nextreturn True
写一个python简洁版本:
# Definition for singly-linked list.
# class ListNode:
# def __init__(self, x):
# self.val = x
# self.next = Noneclass Solution:def hasCycle(self, head: Optional[ListNode]) -> bool:fast = slow = headwhile slow and fast and fast.next.next:slow = slow.nextfast = fast.next.nextif slow is fast:return Truereturn False
方法2:哈希表
哈希表来存储所有已经访问过的节点。每次我们到达一个节点,如果该节点已经存在于哈希表中,则说明该链表是环形链表,否则就将该节点加入哈希表中。重复这一过程,直到我们遍历完整个链表即可。
/*** Definition for singly-linked list.* struct ListNode {* int val;* ListNode *next;* ListNode(int x) : val(x), next(NULL) {}* };*/
class Solution {
public:bool hasCycle(ListNode *head) {unordered_set<ListNode*> seen;while (head != nullptr){if (seen.count(head)){return true;}seen.insert(head);head = head->next;}return false;}
};
# Definition for singly-linked list.
# class ListNode:
# def __init__(self, x):
# self.val = x
# self.next = Noneclass Solution:def hasCycle(self, head: Optional[ListNode]) -> bool:if (head == None or head.next == None):return Falseseen = set()while (head):if head in seen:return Trueseen.add(head)head = head.nextreturn False
142 环形链表2
142. 环形链表 II - 力扣(LeetCode) (leetcode-cn.com)https://leetcode-cn.com/problems/linked-list-cycle-ii/
方法1:哈希表
/*** Definition for singly-linked list.* struct ListNode {* int val;* ListNode *next;* ListNode(int x) : val(x), next(NULL) {}* };*/
class Solution {
public:ListNode *detectCycle(ListNode *head) {unordered_set<ListNode*> visit;if (head == nullptr || head->next == nullptr){return nullptr;}while (head != nullptr){if (visit.count(head)){return head;}visit.insert(head);head = head->next;}return nullptr;}
};
# Definition for singly-linked list.
# class ListNode:
# def __init__(self, x):
# self.val = x
# self.next = Noneclass Solution:def detectCycle(self, head: ListNode) -> ListNode:visit = set()if not head or not head.next:return Nonewhile (head):if head in visit:return headvisit.add(head)head = head.nextreturn None
注:暂时不明白
扩展:哈希表基础及其在c++和python中的基本语法。
set集合
官方文档:
内置类型 — Python 3.10.3 文档https://docs.python.org/zh-cn/3/library/stdtypes.html?highlight=set#set
[unordered_map - C++ Referencehttp://[unordered_map - C++ Reference (cplusplus.com)](http://www.cplusplus.com/reference/unordered_map/unordered_map/?kw=unordered_map)
集合是按照特定顺序存储唯一元素的容器。
在集合中,元素的值也标识它(值本身就是键,类型为 T),并且每个值必须是唯一的。
集合中元素的值不能在容器中修改一次(元素始终为 const),但可以从容器中插入或删除它们。 在内部,集合中的元素始终按照其内部比较对象(比较类型)指示的特定严格弱排序标准进行排序。
set 容器通常比 unordered_set 容器通过键访问单个元素要慢,但它们允许根据它们的顺序对子集进行直接迭代。
集合通常实现为二叉搜索树。
基本函数(c++):
- begin()--返回指向第一个元素的迭代器
- clear()--清除所有元素
- count()--返回某个值元素的个数//值为1或者0
- empty()--如果集合为空,返回true
- end()--返回指向最后一个元素的迭代器
- equal_range()--返回集合中与给定值相等的上下限的两个迭代器
- erase()--删除集合中的元素
- find()--返回一个指向被查找到元素的迭代器
- get_allocator()--返回集合的分配器
- insert()--在集合中插入元素
- lower_bound()--返回指向大于(或等于)某值的第一个元素的迭代器
- key_comp()--返回一个用于元素间值比较的函数
- max_size()--返回集合能容纳的元素的最大限值
- rbegin()--返回指向集合中最后一个元素的反向迭代器
- rend()--返回指向集合中第一个元素的反向迭代器
- size()--集合中元素的数目
- swap()--交换两个集合变量
- upper_bound()--返回大于某个值元素的迭代器
- value_comp()--返回一个用于比较元素间的值的函数1.
多看c++官方文档:
set - C++ Reference (cplusplus.com)
基本函数(python)
多看官方文档:
内置类型 — Python 3.10.2 文档
set和unordered_set区别以及适用情况
(17条消息) set和unordered_set区别以及适用情况_小乾的计算机学习之路-CSDN博客_set unordered_set
致谢
【反转链表】:双指针,递归,妖魔化的双指针 - 反转链表 - 力扣(LeetCode) (leetcode-cn.com)(15条消息) 链表 - 哑节点_Hi-YOLO的博客-CSDN博客_哑节点
(17条消息) Python集合(set)的操作及方法_小七的博客-CSDN博客_python set
(22条消息) 链表(图文详解)_糊涂糖僧的博客-CSDN博客_链表
【数据结构与算法】03 链表(基础知识+面试高频leetcode题目)相关推荐
- 【超全汇总】学习数据结构与算法,计算机基础知识,看这篇就够了【ZT帅地】2020-3-7
https://blog.csdn.net/m0_37907797/article/details/104029002 由于文章有点多,并且发的文章也不是一个系列一个系列发的,不过我的文章大部分都是围 ...
- 计算机基础知识数据结构与算法,(计算机基础知识)[数据结构与算法] 图
第六章 图 6.1 图的定义和基本术语 图: G=(V,E) Graph = (Vertex, Edge) V: 顶点(数据元素)的有穷非空集合 E: 边的有穷集合 完全图: 任意两个点都有一条边相连 ...
- Interview之AI:人工智能领域岗位求职面试—人工智能算法工程师知识框架及课程大纲(AI基础之数学基础/数据结构与算法/编程学习基础、ML算法简介、DL算法简介)来理解技术交互流程
Interview之AI:人工智能领域岗位求职面试-人工智能算法工程师知识框架及课程大纲(AI基础之数学基础/数据结构与算法/编程学习基础.ML算法简介.DL算法简介)来理解技术交互流程 目录 一.A ...
- 一文通数据结构与算法之——链表+常见题型与解题策略+Leetcode经典题
文章目录 1 链表 1.1 常见题型及解题策略 1.1.1 LeetCode中关于链表的题目有以下五种类型题: 1.1.2 解题策略 1.2 链表的基本内容 1.2.1 链表的基本结构: 1.2.2 ...
- 数据结构与算法 内核链表实现商品购物系统项目+Makefile
数据结构与算法 内核链表实现商品购物系统项目 第一章 项目实现思维 [1]编译介绍 [2]框架思维 第二章 Makefile编写 第三章 代码编写实现 [1]favorite.txt文件 [2]his ...
- python定义链表节点_Python数据结构与算法之链表定义与用法实例详解【单链表、循环链表】...
本文实例讲述了Python数据结构与算法之链表定义与用法.分享给大家供大家参考,具体如下: 本文将为大家讲解: (1)从链表节点的定义开始,以类的方式,面向对象的思想进行链表的设计 (2)链表类插入和 ...
- mysql系列问答题_(2)MySQL运维基础知识面试问答题
面试题001:请解释关系型数据库概念及主要特点? 面试题002:请说出关系型数据库的典型产品.特点及应用场景? 面试题003:请解释非关系型数据库概念及主要特点? 面试题004:请说出非关系型数据库的 ...
- 数据结构与算法之链表结构寻找p、q最近的公共祖先
链表结构,寻找p.q最近的公共祖先 数据结构与算法之链表结构寻找p.q最近的公共祖先 链表结构,寻找p.q最近的公共祖先 问题 想法 代码 问题 设一棵二叉树的结点结构为(LLINK, INFO, R ...
- 数据结构与算法--单链表相关面试题
此文章仅作为自己学习过程中的记录和总结,同时会有意地去用英文来做笔记,一些术语的英译不太准确,内容如有错漏也请多指教,谢谢! 一.概述 获取单链表的有效元素个数[新浪面试题1] 获取单链表倒数第k个结 ...
最新文章
- 用 Flask 来写个轻博客 (14) — M(V)C_实现项目首页的模板
- 面试总结-腾讯产品群面
- 过程化技术:打造「开放世界」的秘密
- Android 自定义ViewGroup
- Pycharm配置运行/调试时的工作目录
- JAVA学生宿舍管理系统
- 7、乐趣国学—趣谈“圣贤”
- MATLAB绘图:导出矢量图
- python自带的库有哪些_python自带库
- 蓝光手游大师极速版 V1.0.82
- jqgrid 加载mysql数据_利用jqgrid+加mysql的text类型实现简单自定义数据模型
- Win10部分引起鼠标卡顿间歇性失灵的原因
- 云洲智能,能否成为科创板无人船艇第一股?
- js中类似`${xx,xxxy}`的语句
- 国标28181:什么是SIP协议
- vue中DatePicker从前台到后台日期偶尔差一天
- mybatis if-else(chose when otherwise )
- 未能检测服务器连接失败,被控链接失败处理检查方法
- mysql2008百度云_SQLServer数据库之SQL Server 2008R2 企业版 百度云下载地址
- CLIPCAP:图生文