You are given an integer n
and an array sick
sorted in increasing order, representing positions of infected people in a line of n
people.
At each step, one uninfected person adjacent to an infected person gets infected. This process continues until everyone is infected.
An infection sequence is the order in which uninfected people become infected, excluding those initially infected.
Return the number of different infection sequences possible, modulo 109+7
.
Example 1:
Input: n = 5, sick = [0,4]
Output: 4
Explanation:
There is a total of 6 different sequences overall.
[1,2,3]
, [1,3,2]
, [3,2,1]
and [3,1,2]
.[2,3,1]
and [2,1,3]
are not valid infection sequences because the person at index 2 cannot be infected at the first step.Example 2:
Input: n = 4, sick = [1]
Output: 3
Explanation:
There is a total of 6 different sequences overall.
[0,2,3]
, [2,0,3]
and [2,3,0]
.[3,2,0]
, [3,0,2]
, and [0,3,2]
are not valid infection sequences because the infection starts at the person at index 1, then the order of infection is 2, then 3, and hence 3 cannot be infected earlier than 2.Constraints:
2 <= n <= 105
1 <= sick.length <= n - 1
0 <= sick[i] <= n - 1
sick
is sorted in increasing order.When you get asked this question in a real-life environment, it will often be ambiguous (especially at FAANG). Make sure to ask these questions in that case:
The brute force strategy for this problem involves exploring every single potential infection sequence. We essentially try out all the possible orderings in which infections could spread. By examining each ordering, we identify and count the ones that result in a valid infection scenario.
Here's how the algorithm would work step-by-step:
import itertools
def count_infection_sequences_brute_force(initial_infected, can_infect):
number_of_individuals = len(can_infect)
infection_sequence_count = 0
# Generate all possible orderings of individuals
for infection_order in itertools.permutations(range(number_of_individuals)):
infected = set(initial_infected)
valid_sequence = True
# Simulate the infection spreading process
for individual_index in infection_order:
if individual_index in infected:
continue
can_be_infected = True
for source_index in initial_infected:
if source_index == individual_index:
continue
if source_index in can_infect[individual_index]:
can_be_infected = False
break
infectable_neighbors = set(can_infect[individual_index]) & infected
if not infectable_neighbors:
continue
# Infection rule: infected neighbors must be able to infect the current individual
can_infect_all = all(
individual_index in can_infect[source_index] for source_index in infectable_neighbors
)
if can_infect_all:
infected.add(individual_index)
# Ensure the final infected set matches
final_infected = set()
queue = list(initial_infected)
visited = set(initial_infected)
while queue:
current_person = queue.pop(0)
final_infected.add(current_person)
for next_person in range(number_of_individuals):
if (next_person not in visited and
current_person in can_infect[next_person] and
next_person in can_infect[current_person]):
queue.append(next_person)
visited.add(next_person)
if infected == final_infected:
infection_sequence_count += 1
return infection_sequence_count
The problem asks us to count the valid ways an infection can spread. The key idea is to use dynamic programming to break down the problem into smaller, overlapping subproblems, avoiding redundant calculations.
Here's how the algorithm would work step-by-step:
def count_infection_sequences(number_of_healthy,
initial_infections):
# Factorial function for calculating permutations
def factorial(number):
if number == 0:
return 1
else:
result = 1
for i in range(1, number + 1):
result *= i
return result
# Calculate the number of infection sequences
if number_of_healthy < 0 or initial_infections < 0:
return 0
# Number of ways to order the infections
number_of_sequences = factorial(number_of_healthy)
# This handles cases with no healthy individuals
if number_of_healthy == 0:
return 1
# Sequences are only relevant if there are healthy people
return number_of_sequences
Case | How to Handle |
---|---|
n <= 0 or k <= 0 | Return 0 as no sequence is possible with non-positive length or initial infections. |
k > n | Return 0 as the number of initially infected positions cannot be greater than the sequence length. |
n = 1, k = 1 | Return 1 as there is only one infected position and the sequence is already fully infected. |
n = 2, k = 1 | Return 2 as there are two possible sequences depending on which initial position infects the other. |
Integer overflow during intermediate calculations (factorial, powers) | Use modulo operator (10^9 + 7) after each multiplication and power operation to prevent overflow. |
Large n and k values leading to high computational complexity | Optimize the calculations using dynamic programming or memoization to avoid redundant computations. |
k = n (all positions initially infected) | Return 1, as there is only one possible sequence: the initial state. |
n is very large and using naive factorial calculation would be too slow | Precompute factorials and inverse factorials modulo 10^9+7 for optimization, and avoid recalculating them each time. |