LeetCode 题解工作台
统计感冒序列的数目
给你一个整数 n 和一个下标从 0 开始的整数数组 sick ,数组按 升序 排序。 有 n 位小朋友站成一排,按顺序编号为 0 到 n - 1 。数组 sick 包含一开始得了感冒的小朋友的位置。如果位置为 i 的小朋友得了感冒,他会传染给下标为 i - 1 或者 i + 1 的小朋友, 前提 是…
3
题型
5
代码语言
3
相关题
当前训练重点
困难 · 数组·数学
答案摘要
根据题目描述,感冒的小朋友把还没有感冒的小朋友划分成了若干个连续段。我们可以用一个数组 记录每一段不感冒的小朋友的认识,不感冒人数一共有 $s = \sum_{i=0}^{k} nums[k]$ 人。我们可以发现,感冒序列的数目就是 个不同元素的全排列数,即 。 假设每一段不感冒小朋友只有一种传播方案,那么一共有 $\frac{s!}{\prod_{i=0}^{k} nums[k]!}$ 种感…
Interview AiBoxInterview AiBox 实时 AI 助手,陪你讲清 数组·数学 题型思路
题目描述
给你一个整数 n 和一个下标从 0 开始的整数数组 sick ,数组按 升序 排序。
有 n 位小朋友站成一排,按顺序编号为 0 到 n - 1 。数组 sick 包含一开始得了感冒的小朋友的位置。如果位置为 i 的小朋友得了感冒,他会传染给下标为 i - 1 或者 i + 1 的小朋友,前提 是被传染的小朋友存在且还没有得感冒。每一秒中, 至多一位 还没感冒的小朋友会被传染。
经过有限的秒数后,队列中所有小朋友都会感冒。感冒序列 指的是 所有 一开始没有感冒的小朋友最后得感冒的顺序序列。请你返回所有感冒序列的数目。
由于答案可能很大,请你将答案对 109 + 7 取余后返回。
注意,感冒序列 不 包含一开始就得了感冒的小朋友的下标。
示例 1:
输入:n = 5, sick = [0,4] 输出:4 解释:一开始,下标为 1 ,2 和 3 的小朋友没有感冒。总共有 4 个可能的感冒序列: - 一开始,下标为 1 和 3 的小朋友可以被传染,因为他们分别挨着有感冒的小朋友 0 和 4 ,令下标为 1 的小朋友先被传染。 然后,下标为 2 的小朋友挨着感冒的小朋友 1 ,下标为 3 的小朋友挨着感冒的小朋友 4 ,两位小朋友都可以被传染,令下标为 2 的小朋友被传染。 最后,下标为 3 的小朋友被传染,因为他挨着感冒的小朋友 2 和 4 ,感冒序列为 [1,2,3] 。 - 一开始,下标为 1 和 3 的小朋友可以被传染,因为他们分别挨着感冒的小朋友 0 和 4 ,令下标为 1 的小朋友先被传染。 然后,下标为 2 的小朋友挨着感冒的小朋友 1 ,下标为 3 的小朋友挨着感冒的小朋友 4 ,两位小朋友都可以被传染,令下标为 3 的小朋友被传染。 最后,下标为 2 的小朋友被传染,因为他挨着感冒的小朋友 1 和 3 ,感冒序列为 [1,3,2] 。 - 感冒序列 [3,1,2] ,被传染的顺序:[0,1,2,3,4] => [0,1,2,3,4] => [0,1,2,3,4] => [0,1,2,3,4] 。 - 感冒序列 [3,2,1] ,被传染的顺序:[0,1,2,3,4] => [0,1,2,3,4] => [0,1,2,3,4] => [0,1,2,3,4] 。
示例 2:
输入:n = 4, sick = [1] 输出:3 解释:一开始,下标为 0 ,2 和 3 的小朋友没有感冒。总共有 3 个可能的感冒序列: - 感冒序列 [0,2,3] ,被传染的顺序:[0,1,2,3] => [0,1,2,3] => [0,1,2,3] => [0,1,2,3] 。 - 感冒序列 [2,0,3] ,被传染的顺序:[0,1,2,3] => [0,1,2,3] => [0,1,2,3] => [0,1,2,3] 。 - 感冒序列 [2,3,0] ,被传染的顺序:[0,1,2,3] => [0,1,2,3] => [0,1,2,3] => [0,1,2,3] 。
提示:
2 <= n <= 1051 <= sick.length <= n - 10 <= sick[i] <= n - 1sick按升序排列。
解题思路
方法一:组合数学 + 乘法逆元 + 快速幂
根据题目描述,感冒的小朋友把还没有感冒的小朋友划分成了若干个连续段。我们可以用一个数组 记录每一段不感冒的小朋友的认识,不感冒人数一共有 人。我们可以发现,感冒序列的数目就是 个不同元素的全排列数,即 。
假设每一段不感冒小朋友只有一种传播方案,那么一共有 种感冒序列。
接下来,我们再考虑每一段不感冒小朋友的传播方案。假设一段不感冒小朋友有 个人,那么他们的传播方案有 种,因为每一次可以从一段的左右两端选择其中一端传播,即:两种选择,一共有 次传播。不过,如果是第一段或者最后一段,那么只有一种选择。
综上所述,总的感冒序列数目为:
最后,我们需要考虑到答案可能很大,需要对 取模。因此,我们需要预处理阶乘和乘法逆元。
时间复杂度 ,其中 是数组 的长度。忽略预处理数组的空间消耗,空间复杂度 。
mod = 10**9 + 7
mx = 10**5
fac = [1] * (mx + 1)
for i in range(2, mx + 1):
fac[i] = fac[i - 1] * i % mod
class Solution:
def numberOfSequence(self, n: int, sick: List[int]) -> int:
nums = [b - a - 1 for a, b in pairwise([-1] + sick + [n])]
ans = 1
s = sum(nums)
ans = fac[s]
for x in nums:
if x:
ans = ans * pow(fac[x], mod - 2, mod) % mod
for x in nums[1:-1]:
if x > 1:
ans = ans * pow(2, x - 1, mod) % mod
return ans
复杂度分析
| 指标 | 值 |
|---|---|
| 时间 | complexity depends on iterating through segments and computing combinatorial numbers, roughly O(n) with precomputed factorials. Space complexity is O(n) to store factorials and segment lengths. |
| 空间 | Depends on the final approach |
面试官常问的追问
外企场景- question_mark
Check how you segment the array and ensure proper boundaries for combinatorial counting.
- question_mark
Be careful with large numbers; modular arithmetic might be necessary.
- question_mark
Discuss how multiplying segment results gives the final sequence count and why this works mathematically.
常见陷阱
外企场景- error
Forgetting to exclude initially infected positions when counting sequences.
- error
Miscounting orders within segments that have multiple infection possibilities.
- error
Not handling edge segments at the ends of the line correctly.
进阶变体
外企场景- arrow_right_alt
Allowing multiple infections per step instead of one at a time changes combinatorial calculations.
- arrow_right_alt
Changing the line to a circular arrangement affects adjacency rules and segment counting.
- arrow_right_alt
Using a tree or graph structure instead of a line introduces more complex infection propagation patterns.