[英雄星球六月集训LeetCode解题日报] 第12日 链表
一、 328. 奇偶链表
链接: 328. 奇偶链表
1. 题目描述
给定单链表的头节点 head ,将所有索引为奇数的节点和索引为偶数的节点分别组合在一起,然后返回重新排序的列表。
第一个节点的索引被认为是 奇数 , 第二个节点的索引为 偶数 ,以此类推。
请注意,偶数组和奇数组内部的相对顺序应该与输入时保持一致。
你必须在 O(1) 的额外空间复杂度和 O(n) 的时间复杂度下解决这个问题
2. 思路分析
要求奇偶分开,因此一次处理两个节点,那我们就设置两个指针一起后移即可。
最后把两段连起来,因此一开始要记录一下偶指针的头。
3. 代码实现
class Solution:
def oddEvenList(self, head: Optional[ListNode]) -> Optional[ListNode]:
if not head or not head.next or not head.next.next:
return head
zero = head
one = one0= head.next
while one and one.next:
zero.next = one.next
zero = zero.next
one.next = zero.next
one = one.next
zero.next = one0
return head
二、 725. 分隔链表
链接: 725. 分隔链表
1. 题目描述
给你一个头结点为 head 的单链表和一个整数 k ,请你设计一个算法将链表分隔为 k 个连续的部分。
每部分的长度应该尽可能的相等:任意两部分的长度差距不能超过 1 。这可能会导致有些部分为 null 。
这 k 个部分应该按照在链表中出现的顺序排列,并且排在前面的部分的长度应该大于或等于排在后面的长度。
返回一个由上述 k 部分组成的数组。
2. 思路分析
- 有点像微信的抢红包算法,每次分配:用当前剩余数量除以剩余格子,
- 计算一个当前的平均值,本题向上取整可保证非升序。
- 更新剩余数量和剩余格子个数。
3. 代码实现
class Solution:
def splitListToParts(self, head: ListNode, k: int) -> List[ListNode]:
if not head :
return [head]*k
cur = head
list_copy = []
while cur:
list_copy.append(cur)
cur = cur.next
length = len(list_copy)
ans = []
i = j = 0 # 数组指针,剩余格子指针
while j < k:
width = ceil((length-i)/(k-j)) # 当前宽度=剩余长度/剩余格子
x = list_copy[i] if i < length else None
ans.append(x)
i += width
if i-1 < length:
list_copy[i-1].next = None
j += 1
return ans
三、 817. 链表组件
链接: 817. 链表组件
1. 题目描述
给定链表头结点 head,该链表上的每个结点都有一个 唯一的整型值 。同时给定列表 nums,该列表是上述链表中整型值的一个子集。
返回列表 nums 中组件的个数,这里对组件的定义为:链表中一段最长连续结点的值(该值必须在列表 nums 中)构成的集合。
2. 思路分析
从例2来看,nums是无序的,可以排序后组合出连续子集也算满足要求。
那么实际上就是求nums中连续的数据组数。
由于链表的数据也是乱序的,因此转换成下标即可。
然后把nums的数转换成链表中映射的下标。
3. 代码实现
class Solution:
def numComponents(self, head: Optional[ListNode], nums: List[int]) -> int:
d = {}
depth = 0
while head:
d[head.val] = depth
depth+= 1
head = head.next
poses = []
for num in nums:
if num in d:
poses.append(d[num])
poses.sort()
n = len(poses)
cnt = [poses[0]]
for i in range(1,n):
if poses[i]-poses[i-1]>1:
cnt.append(poses[i])
return len(cnt)
四、 622. 设计循环队列
链接: 622. 设计循环队列
1. 题目描述
2. 思路分析
题意比较明确。
本题必然是用链表设置头尾虚拟节点最简单,但不符合题意,因为链表的节点申请是重新分配内存的。
题目显然是考察数组模拟,否则没难度了。
- 如果也用头尾指针模拟,可以数组开成k+2,比较好写。(因为头尾指针也要占位置)
- 但是最好写的还是头指针+size,判empty和full都是一行
3. 代码实现
class MyCircularQueue:
def __init__(self, k: int):
self.que = [0] *k
self.k = k
self.head = 0
self.count = 0
def enQueue(self, value: int) -> bool:
if self.isFull():
return False
k = self.k
idx = self.head +self.count
if idx >= k:
idx -= k
self.que[idx] = value
self.count += 1
return True
def deQueue(self) -> bool:
if self.isEmpty():
return False
k = self.k
self.head += 1
if self.head >= k:
self.head -= k
self.count -= 1
return True
def Front(self) -> int:
if self.isEmpty():
return -1
return self.que[self.head]
def Rear(self) -> int:
if self.isEmpty():
return -1
idx = self.head + self.count - 1
return self.que[(idx+self.k)%self.k]
def isEmpty(self) -> bool:
return self.count == 0
def isFull(self) -> bool:
return self.count == self.k