The "Kill Process" problem involves simulating the termination of a process in an operating system, along with all of its child processes (and their descendants). You are given three lists:
pid
: a list of unique process IDs.
ppid
: a list where ppid[i]
is the parent process ID of pid[i]
.
kill
: the process ID of the process you want to terminate.
When you "kill" a process, all of its child processes (and their children, recursively) should also be terminated. The goal is to return a list of all process IDs that will be killed as a result, in any order.
Constraints:
ppid = 0
(the root process).pid
.The core challenge is to efficiently find all descendants of a given process. At first glance, you might think to check, for each process, whether it is a descendant of the process to be killed. However, this would be very inefficient, especially as the number of processes grows.
Instead, it's helpful to think of the processes as forming a tree (or forest) where each process points to its children. If we can quickly look up all children of a process, we can traverse the tree starting from the process to be killed, collecting all descendants along the way.
This naturally suggests building a mapping from parent process IDs to their child process IDs, and then using a traversal (such as BFS or DFS) to gather all processes to kill.
Here’s how we can systematically solve the problem:
pid
and ppid
lists together.
pid
as a child under the corresponding ppid
in a hash map (dictionary).
kill
).
We use a hash map for fast lookups of children given a parent, and a stack/queue for traversal.
Sample Input:
pid = [1, 3, 10, 5]
ppid = [3, 0, 5, 3]
kill = 3
Step 1: Build the Parent-to-Children Map
Step 2: Traverse from kill = 3
Result: All visited processes = [3, 1, 5, 10]
Brute-force Approach:
If you checked every process to see if it is a descendant of kill
by walking up the parent chain, it would take O(N^2) time, where N is the number of processes.
Optimized Approach:
The "Kill Process" problem is a classic tree traversal problem disguised in process management terms. By mapping parents to their children and using a simple traversal, we efficiently gather all processes that should be terminated. The key insight is to represent the process relationships as a tree and use standard traversal algorithms to solve the problem in linear time.
from collections import defaultdict, deque
class Solution:
def killProcess(self, pid, ppid, kill):
tree = defaultdict(list)
for child, parent in zip(pid, ppid):
tree[parent].append(child)
result = []
queue = deque([kill])
while queue:
curr = queue.popleft()
result.append(curr)
for child in tree[curr]:
queue.append(child)
return result
#include <vector>
#include <unordered_map>
#include <queue>
using namespace std;
class Solution {
public:
vector<int> killProcess(vector<int>& pid, vector<int>& ppid, int kill) {
unordered_map<int, vector<int>> tree;
for (size_t i = 0; i < pid.size(); ++i) {
tree[ppid[i]].push_back(pid[i]);
}
vector<int> result;
queue<int> q;
q.push(kill);
while (!q.empty()) {
int curr = q.front(); q.pop();
result.push_back(curr);
for (int child : tree[curr]) {
q.push(child);
}
}
return result;
}
};
import java.util.*;
public class Solution {
public List<Integer> killProcess(List<Integer> pid, List<Integer> ppid, int kill) {
Map<Integer, List<Integer>> tree = new HashMap<>();
for (int i = 0; i < pid.size(); i++) {
tree.computeIfAbsent(ppid.get(i), k -> new ArrayList<>()).add(pid.get(i));
}
List<Integer> result = new ArrayList<>();
Queue<Integer> queue = new LinkedList<>();
queue.add(kill);
while (!queue.isEmpty()) {
int curr = queue.poll();
result.add(curr);
List<Integer> children = tree.get(curr);
if (children != null) {
queue.addAll(children);
}
}
return result;
}
}
/**
* @param {number[]} pid
* @param {number[]} ppid
* @param {number} kill
* @return {number[]}
*/
var killProcess = function(pid, ppid, kill) {
const tree = {};
for (let i = 0; i < pid.length; i++) {
if (!tree[ppid[i]]) tree[ppid[i]] = [];
tree[ppid[i]].push(pid[i]);
}
const result = [];
const queue = [kill];
while (queue.length > 0) {
const curr = queue.shift();
result.push(curr);
if (tree[curr]) {
queue.push(...tree[curr]);
}
}
return result;
};