LeetCode Hot 100 Python (31~40)
K个一组翻转链表:困难
给你链表的头节点 head ,每 k 个节点一组进行翻转,请你返回修改后的链表。
k 是一个正整数,它的值小于或等于链表的长度。如果节点总数不是 k 的整数倍,那么请将最后剩余的节点保持原有顺序。
你不能只是单纯的改变节点内部的值,而是需要实际进行节点交换。
示例 | 1 | 2 |
输入 | head = [1,2,3,4,5], k = 2 | head = [1,2,3,4,5], k = 3 |
输出 | [2,1,4,3,5] | [3,2,1,4,5] |
| |
统计节点个数:
使用 while 循环遍历链表,统计节点总数 n。
初始化哨兵节点:
创建一个哨兵节点 dummy,其 next 指向 head,方便处理头节点。
K 组反转:
使用 while 循环,每次处理 k 个节点。
在每个 k 组内,使用 for 循环反转节点指针。
更新 p0 和 pre 指针,确保链表正确连接。
class Solution:def reverseKGroup(self, head: Optional[ListNode], k: int) -> Optional[ListNode]:# 统计节点个数n = 0cur = headwhile cur:n += 1cur = cur.nextp0 = dummy = ListNode(next=head)pre = Nonecur = head# k 个一组处理while n >= k:n -= kfor _ in range(k): # 同 92 题nxt = cur.nextcur.next = pre # 每次循环只修改一个 next,方便大家理解pre = curcur = nxt# 见视频nxt = p0.nextnxt.next = curp0.next = prep0 = nxtreturn dummy.next
时间复杂度 | 空间复杂度 |
O(n) | O(1) |
其中 n 为链表长度 |
随机链表的复制:中等
给你一个长度为 n 的链表,每个节点包含一个额外增加的随机指针 random ,该指针可以指向链表中的任何节点或空节点。
构造这个链表的 深拷贝。 深拷贝应该正好由 n 个 全新 节点组成,其中每个新节点的值都设为其对应的原节点的值。新节点的 next 指针和 random 指针也都应指向复制链表中的新节点,并使原链表和复制链表中的这些指针能够表示相同的链表状态。复制链表中的指针都不应指向原链表中的节点 。
例如,如果原链表中有 X 和 Y 两个节点,其中 X.random --> Y 。那么在复制链表中对应的两个节点 x 和 y ,同样有 x.random --> y 。
返回复制链表的头节点。
用一个由 n 个节点组成的链表来表示输入/输出中的链表。每个节点用一个 [val, random_index] 表示:
- val:一个表示 Node.val 的整数。
- random_index:随机指针指向的节点索引(范围从 0 到 n-1);如果不指向任何节点,则为 null 。
你的代码 只 接受原链表的头节点 head 作为传入参数。
示例 | |
1 | |
head = [[7,null],[13,0],[11,4],[10,2],[1,0]] | |
[[7,null],[13,0],[11,4],[10,2],[1,0]] | |
2 | |
head = [[1,1],[2,1]] | |
[[1,1],[2,1]] | |
3 | |
head = [[3,null],[3,0],[3,null]] | |
[[3,null],[3,0],[3,null]] |
题意
深拷贝一个链表,要求新链表中的每个节点都是新创建的,并且这些节点的 random 指针都指向新链表中的相应节点。
思路
如果没有 random 指针,只需在遍历链表的同时,依次复制每个节点(创建新节点并复制 val),添加在新链表的末尾。
有 random 指针,问题就变得复杂了,我们需要知道 random 指向的那个节点,在新链表中是哪个节点。
所以必须记录原链表节点到新链表节点的映射(map)。这样可以通过原链表 random 指向的节点,知道新链表的 random 应该指向哪个节点。
难道要用哈希表吗?不需要,我们可以把新链表和旧链表「混在一起」。
例如链表 1→2→3,依次复制每个节点(创建新节点并复制 val 和 next),把新节点直接插到原节点的后面,形成一个交错链表:
如此一来,原链表节点的下一个节点,就是其对应的新链表节点了!
然后遍历这个交错链表,假如节点 1 的 random 指向节点 3,那么就把节点 1′的 random 指向节点 3 的下一个节点 3′,这样就完成了对 random 指针的复制。
最后,从交错链表链表中分离出 1′→2′→3′,即为深拷贝后的链表。做法类似 328. 奇偶链表。
⚠注意:不能只删除节点 1,2,3,因为题目要求原链表的 next 不能修改。(但 Python 可以这么做)
class Solution:def copyRandomList(self, head: 'Optional[Node]') -> 'Optional[Node]':if head is None:return None# 复制每个节点,把新节点直接插到原节点的后面cur = headwhile cur:cur.next = Node(cur.val, cur.next)cur = cur.next.next# 遍历交错链表中的原链表节点cur = headwhile cur:if cur.random:# 要复制的 random 是 cur.random 的下一个节点cur.next.random = cur.random.nextcur = cur.next.next# 遍历交错链表中的新链表节点cur = head.nextwhile cur.next:# 删除原链表的节点,即当前节点的下一个节点cur.next = cur.next.nextcur = cur.next# 返回 head.next 就相当于删除了原链表的头节点return head.next
class Solution:def copyRandomList(self, head: 'Optional[Node]') -> 'Optional[Node]':if head is None:return None# 复制每个节点,把新节点直接插到原节点的后面cur = headwhile cur:cur.next = Node(cur.val, cur.next)cur = cur.next.next# 遍历交错链表中的原链表节点cur = headwhile cur:if cur.random:# 要复制的 random 是 cur.random 的下一个节点cur.next.random = cur.random.nextcur = cur.next.next# 把交错链表分离成两个链表new_head = head.nextcur = headwhile cur.next.next:copy = cur.nextcur.next = copy.next # 恢复原节点的 nextcopy.next = copy.next.next # 设置新节点的 nextcur = cur.nextcur.next = None # 恢复原节点的 nextreturn new_head
时间复杂度 | 空间复杂度 |
O(n) | O(1) |
其中 n 为链表长度 |
排序链遍:中等
给你链表的头结点 head ,请将其按 升序 排列并返回 排序后的链表 。