You have n
processes forming a rooted tree structure. You are given two integer arrays pid
and ppid
, where pid[i]
is the ID of the ith
process and ppid[i]
is the ID of the ith
process's parent.
Each process has only one parent but may have zero or more children. The process with pid[i] == 0
is the root process.
You are also given an integer kill
representing the ID of a process to kill.
You should kill the given process and all of its children. Return a list of the IDs of the processes that will be killed. You may return the answer in any order.
Example 1:
Input: pid = [1,3,10,5], ppid = [3,0,5,3], kill = 5 Output: [5,10] Explanation: The processes form the following tree: 3 / \ 1 5 / 10 Kill 5 and also kill its only child 10.
Example 2:
Input: pid = [1], ppid = [0], kill = 1 Output: [1] Explanation: The root process is killed.
Constraints:
n == pid.length
n == ppid.length
1 <= n <= 5 * 104
0 <= pid[i] <= 5 * 104
0 <= ppid[i] <= 5 * 104
ppid[i] == 0
.pid
are unique.kill
is guaranteed to be in pid
.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:
Imagine a family tree where each person has a unique ID. We want to eliminate a specific person and all their descendants. The brute force approach involves manually checking each person and their relationships to find everyone who needs to be eliminated.
Here's how the algorithm would work step-by-step:
def kill_process_brute_force(process_ids, parent_process_ids, kill_id):
processes_to_kill = [kill_id]
processes_to_check = [kill_id]
# Iterate as long as there are processes to check for children
while processes_to_check:
current_process_id = processes_to_check.pop(0)
# Find children of the current process
for i in range(len(parent_process_ids)):
if parent_process_ids[i] == current_process_id:
child_process_id = process_ids[i]
# Add children to kill list and check list
processes_to_kill.append(child_process_id)
processes_to_check.append(child_process_id)
# This list contains all processes that need to be killed
return processes_to_kill
The most efficient way to solve this problem is to think about which processes are directly controlled by the process we want to eliminate. We can find these 'child' processes and then continue to find their 'children', and so on, until we have identified all processes that will be terminated as a result of killing the initial process.
Here's how the algorithm would work step-by-step:
def kill_process(pid, parent_process_id, kill_id):
process_children = {}
# Build a dictionary to represent the process tree
for i in range(len(parent_process_id)):
parent = parent_process_id[i]
child = pid[i]
if parent not in process_children:
process_children[parent] = []
process_children[parent].append(child)
processes_to_kill = []
# Initiate the kill list with the initial kill_id
processes_to_kill.append(kill_id)
def kill_recursive(process_id_to_kill):
# Kill all the child processes recursively
if process_id_to_kill in process_children:
for child_process in process_children[process_id_to_kill]:
processes_to_kill.append(child_process)
kill_recursive(child_process)
kill_recursive(kill_id)
return processes_to_kill
Case | How to Handle |
---|---|
Null or empty pid and ppid lists | Return an empty list since there are no processes to kill. |
pid and ppid lists have different lengths | Throw an IllegalArgumentException or return an error code indicating invalid input. |
kill process ID not found in pid list | Return an empty list since there's nothing to kill, or the caller may handle this scenario as an exception. |
The kill process ID is the same as the root process ID (0) | Kill all processes since the root process is being terminated. |
Duplicate process IDs in pid list | The tree structure is constructed using the first instance of each process ID, and the behavior will be based on that relationship. |
A process ID has multiple parents (invalid tree structure) | The algorithm should still work, effectively killing all processes descended from all parents; log an error to indicate corrupted data. |
Large input size leading to stack overflow during recursion | Convert the recursive DFS to an iterative DFS using a stack to prevent potential stack overflow errors. |
Integer overflow if process IDs are large | Use long instead of int for storing process IDs if the problem statement allows it to avoid integer overflow. |