{x}
blog image

Kill Process

Solution Explanation: Kill Process

This problem involves traversing a tree structure representing process relationships to identify all processes that need to be killed when a specific process is terminated. The input consists of two arrays: pid (process IDs) and ppid (parent process IDs), and the ID of the process to be killed (kill).

Approach: Depth-First Search (DFS)

The most efficient way to solve this is using Depth-First Search (DFS). DFS systematically explores a tree by going as deep as possible along each branch before backtracking.

  1. Graph Construction: First, we build an adjacency list representation of the process tree. The adjacency list g maps each parent process ID to a list of its child process IDs. This is done by iterating through pid and ppid, associating each process in pid with its parent in ppid.

  2. Depth-First Traversal: We initiate a DFS function (dfs) starting from the kill process. The dfs function does the following:

    • Adds the current process ID (i) to the result list (ans).
    • Recursively calls itself for each child process (j) of the current process. This ensures that all descendants of the kill process are included in the result.
  3. Return Result: The dfs function builds the list of killed processes, which is then returned.

Time and Space Complexity

  • Time Complexity: O(N), where N is the number of processes. This is because we visit each process at most once during the DFS traversal.

  • Space Complexity: O(N) in the worst case. This is due to the space used by the adjacency list g and the recursion stack during the DFS. In the worst case (a completely unbalanced tree), the recursion stack could hold all the nodes in the path to the deepest leaf. The space for ans is also proportional to N in the worst case where all processes are killed.

Code Implementation (Python)

from collections import defaultdict
 
class Solution:
    def killProcess(self, pid: List[int], ppid: List[int], kill: int) -> List[int]:
        g = defaultdict(list)  # Adjacency list to store process relationships
        for i, p in zip(pid, ppid):
            g[p].append(i)
 
        ans = []  # List to store the killed processes
 
        def dfs(i: int):
            ans.append(i)
            for j in g[i]:  # Recursively call dfs for each child
                dfs(j)
 
        dfs(kill)  # Initiate DFS from the kill process
        return ans
 

The implementations in other languages (Java, C++, Go, TypeScript, Rust) follow a very similar structure, adapting the syntax and data structures to the specific language. The core logic of building the adjacency list and performing DFS remains the same.