【实战】ACM 选手图解 LeetCode 设计链表
大家好呀,我是蛋蛋。
今天来设计链表,强行学明白链表的 5 种操作。
板凳摆好,直接开整。
LeetCode 107:设计链表
题意
实现链表的查找、头插法、尾插法、通用插入、删除操作:
- get(index):获取链表中第 index 个节点的值。如果索引无效,则返回-1。
- addAtHead(val):在链表的第一个元素之前添加一个值为 val 的节点。插入后,新节点将成为链表的第一个节点。
- addAtTail(val):将值为 val 的节点追加到链表的最后一个元素。
- addAtIndex(index,val):在链表中的第 index 个节点之前添加值为 val 的节点。如果 index 等于链表的长度,则该节点将附加到链表的末尾。如果 index 大于链表长度,则不会插入节点。如果index小于0,则在头部插入节点。
- deleteAtIndex(index):如果索引 index 有效,则删除链表中的第 index 个节点。
示例
提示
- 1 <= val <= 1000
- 1 <= 操作次数 <= 1000
- 不能使用内置的 LinkedList 库
题目解析
水题,难度中等,考察链表的常规操作。
如果对链表还不太熟悉,请看下面这篇文章:
ACM 选手带你玩转链表!
仔细来看,这道题主要涉及 5 种操作:
- 查找链表第 index 个节点的值
- 在链表的第一个节点前插入一个节点
- 在链表的最后一个节点后插入一个节点
- 在链表的第 index 节点前插入一个节点
- 删除链表的第 index 个节点。
这 5 种包含了链表的常见增删查操作,是刚学完链表的臭宝们及时巩固知识的绝佳练习题。
这道题我用带头节点的单链表来实现。
头节点,可能很多人叫做哨兵节点,放在第一个元素的节点之前,数据域一般没意义。
图解
链表题呢,为了方便后续的操作,一般上来先定义一个简单的节点类:
# 自定义单节点
class Node:def __init__(self, data):self.val = dataself.next = None
链表类里初始化头节点和链表长度。
def __init__(self):"""Initialize your data structure here."""# 头节点self.head = Node(0)# 保存链表长度self.length = 0
get(index) ,查找节点,没啥好说的,就是傻傻的从第 1 个节点开始找。时间复杂度 O(n)。
addAtHead(val) ,在链表第一个节点前插入一个节点,很好插,找到第一个节点的前驱节点就好,在这就是头节点。
因为就在第 1 个,所以时间复杂度 O(1)。
**链表插入一定切记:插入操作的顺序不能改变!**切记!
一定是待插入节点的后继指针先指,然后前驱节点再指向待插入节点。
在下图对应的是值为 10 的节点先指向值为 11 的节点,然后值为 0 的头节点再指向值为 10 的节点。
同理,addAtTail(val) 在链表最后一个节点后插入节点,也很简单,要插入的节点位置的前驱节点就是最后一个节点。
因为在最后一个,时间复杂度 O(n)。
addAtIndex(index, val),在链表的第 index 节点前插入一个节点,其实这个就是插入的通用操作。
同样从第一个节点开始依次查找,时间复杂度 O(n)。
addAtHead(val) 相当于 addAtIndex(0, val)。
addAtTail(val) 相当于 addAtIndex(length, val)。
deleteAtIndex(index),删除链表的第 index 个节点,同样是找到要删除节点的前驱节点,通过改变节点后继指针来删除。
同理,删除链表的时间复杂度也是 O(n)。
代码实现
Python 代码实现
# 自定义单节点
class Node:def __init__(self, data):self.val = dataself.next = Noneclass MyLinkedList:def __init__(self):"""Initialize your data structure here."""# 头节点self.head = Node(0)# 保存链表长度self.length = 0def get(self, index: int) -> int:"""Get the value of the index-th node in the linked list. If the index is invalid, return -1."""# 判断输入的索引是否有效if index < 0 or index >= self.length:return -1p = self.headi_index = 0# range 是左闭右开区间,相当于[0,index+1)for _ in range(index + 1):p = p.nextreturn p.valdef addAtHead(self, val: int) -> None:"""Add a node of value val before the first element of the linked list. After the insertion, the new node will be the first node of the linked list."""return self.addAtIndex(0, val)def addAtTail(self, val: int) -> None:"""Append a node of value val to the last element of the linked list."""return self.addAtIndex(self.length, val)def addAtIndex(self, index: int, val: int) -> None:"""Add a node of value val before the index-th node in the linked list. If index equals to the length of linked list, the node will be appended to the end of linked list. If index is greater than the length, the node will not be inserted."""# 特殊情况 index < 0 和 index = 0,则说明是头插法if index < 0:index = 0if index > self.length:returnp = self.headadd_node = Node(val)# 找到第 index 个节点的前驱节点for _ in range(index):p = p.nextadd_node.next = p.nextp.next = add_node# 插入节点,链表长度 +1self.length += 1def deleteAtIndex(self, index: int) -> None:"""Delete the index-th node in the linked list, if the index is valid."""# 判断输入的索引是否有效if index < 0 or index >=self.length:returnp = self.head# 找到要删除节点的前驱节点和要删除的节点for _ in range(index + 1):# 前驱节点pre = p# 要删除节点p = p.nextpre.next = p.next# 释放删除节点的内存p = None# 删除节点,链表长度 -1self.length -= 1# Your MyLinkedList object will be instantiated and called as such:
# obj = MyLinkedList()
# param_1 = obj.get(index)
# obj.addAtHead(val)
# obj.addAtTail(val)
# obj.addAtIndex(index,val)
# obj.deleteAtIndex(index)
好啦,图解设计链表到这就结束啦。
基础薄弱的臭宝好好思考下这道题,想明白了,就踏出学好链表的第一步啦。
看完的是真爱,点赞在看留言么么哒给本蛋起飞~
我是蛋蛋,我们下次见!
推荐阅读
设计链表的实现.您可以选择使用单链表或双链表.单链表中的节点应该具有两个属性:val 和 next.val 是当前节点的值,next 是指向下一个节点的指针/引用.如果要使用双向链表,则还需要一个属性 ... 文章目录 一.编程题:707. 设计链表(双向链表-带头尾双结点) 1.题目描述 2.示例1: 3.提示: 二.解题思路 1.思路 2.复杂度分析: 3.算法图解(双向链表) 三.代码实现 三.单向链 ... 题目英文 Merge k sorted linked lists and return it as one sorted list. Analyze and describe its complexi ... 此题涵盖了链表的常见操作,是练习链表操作非常好的一道题目 此题涵盖了链表的常见操作,是练习链表操作非常好的一道题目 此题涵盖了链表的常见操作,是练习链表操作非常好的一道题目 题目描述: 设计链表的实现 ... 文章目录 图解LeetCode刷题计划 1.写在前面 2.题目 3.正文 4.代码 图解LeetCode刷题计划 1.写在前面 手绘漫画系列正式上线!!!"图解LeetCode刷题计划&qu ... 文章目录 图解LeetCode刷题计划 1.写在前面 2.题目 3.正文 4.代码 图解LeetCode刷题计划 1.写在前面 手绘漫画系列正式上线!!!"图解LeetCode刷题计划&qu ... 文章目录 图解LeetCode刷题计划 1.写在前面 2.题目 3.正文 4.代码 图解LeetCode刷题计划 1.写在前面 手绘漫画系列正式上线!!!"图解LeetCode刷题计划&qu ... 学算法,刷力扣,加油卷,进大厂! 题目描述 力扣题目链接 设计链表的实现.您可以选择使用单链表或双链表.单链表中的节点应该具有两个属性:val 和 next.val 是当前节点的值,next 是指向下 ... 设计链表的实现.您可以选择使用单链表或双链表.单链表中的节点应该具有两个属性:val 和 next.val 是当前节点的值,next 是指向下一个节点的指针/引用.如果要使用双向链表,则还需要一个属性 ...【实战】ACM 选手图解 LeetCode 设计链表相关推荐
最新文章
热门文章