Leetcode尊享面试100题
4 链表
链表是物理存储单元上非连续的、非顺序的存储结构,数据元素的逻辑顺序是通过链表的指针地址实现。
结点包括两个部分:(1)存储数据元素的数据域(内存空间),(2)存储指向下一个结点地址的指针域。
链表分为: (1)单链表 (2)双链表 (3)单向循环链表 (4)双向循环链表
4.1 举例: 反转链表
给你单链表的头节点 head ,请你反转链表,并返回反转后的链表
输入:head = [1,2,3,4,5]
输出:[5,4,3,2,1]
输入:head = [1,2]
输出:[2,1]
示例 3:
输入:head = []
输出:[]
根据链表的定义,其每个节点都包含两个域,一个为信息域:存储元素,一个为链接域:存储下一节点的地址,最后一个节点的链接域指向一个空值。
每一步循环中,都将原列表中cur.next链接域存放的地址指向其前一个节点,直至cur=Null,pre指向最后一个节点。
循环后,原链表中,最后一个节点中指向的下一个节点为原倒数第二个节点,以此类推,原列表的第一个节点指向Null;pre即相当于头节点,返回pre,相当于将原链表反转
1、迭代需要三个指针,pre,cur,nxt,分别按顺序指向三个节点
2、三个指针的初始化:pre指向空节点,cur指向头结点head,nxt指向head.next; 因为head.next可能不存在,nxt在循环中定义,这样如果head为空就不会进入循环
3、迭代过程
- nxt指向cur.next
- cur.next指向pre
- pre移动到cur位置
- cur移动到nxt位置
4、当cur为空时,返回pre
class Solution:
def reverseList(self, head: ListNode) -> ListNode:
pre = None
cur = head
while cur:
next_temp= cur.next #保存当前节点的下一个节点,防止丢失
cur.next = pre #将当前节点的指针指向前一个节点,实现反转操作 next用来存放下一个节点的位置
#指针存放地址(位置信息) pre cur的位置信息向前移
pre = cur #将 pre 指针指向当前节点,为下一次迭代做准备
cur = next_temp #将当前节点指针移动到下一个节点。
return pre
4.1 删除链表 M 个节点之后的 N 个节点
题目描述
给定链表 head
和两个整数 m
和 n
. 遍历该链表并按照如下方式删除节点:
- 开始时以头节点作为当前节点.
- 保留以当前节点开始的前
m
个节点. - 删除接下来的
n
个节点. - 重复步骤 2 和 3, 直到到达链表结尾.
在删除了指定结点之后, 返回修改过后的链表的头节点.
示例 1:
输入: head = [1,2,3,4,5,6,7,8,9,10,11,12,13], m = 2, n = 3
输出: [1,2,6,7,11,12]
解析: 保留前(m = 2)个结点, 也就是以黑色节点表示的从链表头结点开始的结点(1 ->2).
删除接下来的(n = 3)个结点(3 -> 4 -> 5), 在图中以红色结点表示.
继续相同的操作, 直到链表的末尾.
返回删除结点之后的链表的头结点.
示例 2:
输入: head = [1,2,3,4,5,6,7,8,9,10,11], m = 1, n = 3
输出: [1,5,9]
解析: 返回删除结点之后的链表的头结点.
示例 3:
输入: head = [1,2,3,4,5,6,7,8,9,10,11], m = 3, n = 1
输出: [1,2,3,5,6,7,9,10,11]
示例 4:
输入: head = [9,3,7,7,9,10,8,2], m = 1, n = 2
输出: [9,7,8]
思路分析
哑节点(dummy node)是在链表的头部或尾部添加一个额外的节点,用于简化链表操作和处理边界情况。它不存储具体的数据,只起到一个辅助作用
代码描述
class Solution:
def deleteNodes(self, head: ListNode, m: int, n: int) -> ListNode:
if not head:
return None
# 创建一个哑节点作为新链表的头部
dummy = ListNode(0)
#将哑节点的下一个指针指向原链表的头部。
dummy.next = head
# 定义两个指针,cur用于遍历链表,prev用于连接前后节点
cur = dummy
prev = dummy
#当 当前节点不为空时,进入循环
while cur:
# 保留前m个节点
# 每经过一个节点,cur和prev指针都向后移动一位
for _ in range(m):
if cur:
prev = cur
cur = cur.next
# 删除接下来的n个节点
# 删除接下来的n个节点,每删除一个节点,cur指针向后移动一位。
for _ in range(n):
if cur and cur.next:
cur.next = cur.next.next
else:
break
# 进入下一轮迭代
#将prev的下一个指针指向当前的cur,连接链表
prev.next = cur
cur.next = cur.next.next
将当前节点的 next 指针指向当前节点的下一个节点的下一个节点,即跳过了当前节点的下一个节点,实现了删除操作。通过这种方式,将当前节点与下一个节点断开连接,然后让 cur 指针继续指向链表中的下一个节点,达到删除的效果。
例如,如果当前节点是 A,它的下一个节点是 B,我们执行 cur.next = cur.next.next,那么 A 的 next 指针将直接指向 B 的下一个节点,跳过了 B。这样就在不破坏链表结构的情况下,实现了删除 B 节点的操作。