964 字
5 分钟
代码随想录算法训练营第三天 | 链表 Part01

链表基础#

  • 链表节点的存储是非连续的,每个节点包含一个指针域和一个数据域。
  • 链表的缺点是访问元素的时间复杂度为 O(n),而数组可以在 O(1) 时间内访问任意元素。
  • 链表的优点是插入和删除操作的时间复杂度为 O(1),而数组在这方面较慢。

虚拟头结点#

  • 虚拟头结点是一个额外的节点,通常用于简化链表操作,避免处理空链表或单节点链表的特殊情况。
  • 在链表操作中,使用虚拟头结点可以使得代码更简洁,减少边界条件的判断。

203. 移除链表元素#

LeetCode 203. 移除链表元素

class Solution:
def removeElements(self, head: Optional[ListNode], val: int) -> Optional[ListNode]:
# 设置虚拟头结点,next 指向原链表头节点
dummy = ListNode(next=head)
cur = dummy
# 遍历链表,删除值等于 val 的节点
while cur.next:
if cur.next.val == val:
# 删除节点:跳过当前节点的下一个节点
cur.next = cur.next.next
else:
# 只有不删除时才移动指针
cur = cur.next
return dummy.next

双向链表#

  • 双向链表的每个节点包含两个指针:一个指向前一个节点,一个指向后一个节点。
  • 双向链表允许从任意方向遍历,适用于需要频繁插入和删除操作的场景。

707. 设计链表#

LeetCode 707. 设计链表

# 定义双向链表节点
class ListNode:
def __init__(self, val=0, prev=None, next=None):
self.val = val
self.prev = prev
self.next = next
class MyLinkedList:
def __init__(self):
# 初始化为空链表
self.head = None
self.tail = None
self.length = 0
def get(self, index: int) -> int:
# index 的范围 [0, length - 1]
if index < 0 or index >= self.length:
return -1
# 从头节点开始遍历
cur = self.head
for _ in range(index):
cur = cur.next
return cur.val
def addAtHead(self, val: int) -> None:
new_node = ListNode(val)
if self.length == 0:
# 空链表,head 和 tail 都指向新节点
self.head = self.tail = new_node
else:
new_node.next = self.head
self.head.prev = new_node
self.head = new_node
self.length += 1
def addAtTail(self, val: int) -> None:
new_node = ListNode(val)
if self.length == 0:
# 空链表,head 和 tail 都指向新节点
self.head = self.tail = new_node
else:
new_node.prev = self.tail
self.tail.next = new_node
self.tail = new_node
self.length += 1
def addAtIndex(self, index: int, val: int) -> None:
# index 的范围 [0, length]
if index < 0 or index > self.length:
return
if index == 0:
self.addAtHead(val)
elif index == self.length:
# self.length - 1 指向尾节点,而是 self.length 指向新节点的尾部
self.addAtTail(val)
else:
# 插入到中间位置
cur = self.head
for _ in range(index - 1):
cur = cur.next
new_node = ListNode(val)
new_node.next = cur.next
new_node.prev = cur
cur.next.prev = new_node
cur.next = new_node
self.length += 1
def deleteAtIndex(self, index: int) -> None:
# index 的范围 [0, length - 1]
if index < 0 or index >= self.length:
return
if self.length == 1:
# ⚠️ 容易被忽视,删除唯一节点
self.head = self.tail = None
elif index == 0:
# 删除头节点
self.head = self.head.next
self.head.prev = None
elif index == self.length - 1:
# 删除尾节点
self.tail = self.tail.prev
self.tail.next = None
else:
# 删除中间节点
cur = self.head
for _ in range(index):
cur = cur.next
cur.prev.next = cur.next
cur.next.prev = cur.prev
self.length -= 1

链表翻转#

  • 链表翻转是将链表的方向反转,使得原来的尾节点变为头节点,头节点变为尾节点。

206. 反转链表(迭代法)#

LeetCode 206. 反转链表

class Solution:
def reverseList(self, head: Optional[ListNode]) -> Optional[ListNode]:
prev, cur = None, head
# 当 cur 为 None 时,prev 指向链表的最后一个节点,即新的头节点
while cur:
next_node = cur.next # 暂存下一节点
cur.next = prev # 当前节点指向前一节点(反转)
prev = cur
cur = next_node
return prev

206. 反转链表(递归法)#

LeetCode 206. 反转链表

class Solution:
def reverseList(self, head: Optional[ListNode]) -> Optional[ListNode]:
return self.reverse(head, None)
def reverse(self, cur: Optional[ListNode], prev: Optional[ListNode]) -> Optional[ListNode]:
if not cur:
return prev
temp = cur.next # 暂存下一节点
cur.next = prev # 当前节点指向前一节点(反转)
# 新头节点是由最深层的递归调用产生的。如果不用 return 将它层层向上传递,最终就会丢失
return self.reverse(temp, cur)
代码随想录算法训练营第三天 | 链表 Part01
https://fuwari.vercel.app/posts/code_musings_day_three/
作者
Jarrett
发布于
2025-06-13
许可协议
CC BY-NC-SA 4.0