殺死進程-LeetCode-582

英文版算法

582. Kill Process
Given n processes, each process has a unique PID (process id) and its PPID (parent process id).數組

Each process only has one parent process, but may have one or more children processes. This is just like a tree structure. Only one process has PPID that is 0, which means this process has no parent process. All the PIDs will be distinct positive integers.函數

We use two list of integers to represent a list of processes, where the first list contains PID for each process and the second list contains the corresponding PPID.ui

Now given the two lists, and a PID representing a process you want to kill, return a list of PIDs of processes that will be killed in the end. You should assume that when a process is killed, all its children processes will be killed. No order is required for
the final answer.this

Example 1:spa

Input: 
pid = [1, 3, 10, 5]
ppid = [3, 0, 5, 3]
kill = 5
Output: [5,10]
Explanation: 
   3
  / \
  1 5
    /
   10
Kill 5 will also kill 10.

Note:code

  • - The given kill id is guaranteed to be one of the given PIDs.
  • - n >= 1.

 

中文版
給你n個進程,每一個進程都有一個惟一的PID(process id)和PPID(parent process id)。每一個進程最多隻有一個父進程,但可能有多個子進程。若是一個進程的PPID爲0,表示它沒有父進程。若是一個進程被殺死,那麼它的子進程也會被殺死。輸入兩個相同長度的整數鏈表,第一個鏈表是每一個進程的PID,第二個鏈表是對應位置進程的PPID,再輸入一個將被殺死的進程的PID,請輸出全部將被殺死的進程的PID。blog

例如,輸入的PID鏈表爲[1, 3, 10, 5],PPID鏈表爲[3, 0, 5, 3],將被殺死的進程的PID爲5,那麼最終被殺死的進程有兩個,PID分別爲5和10。這是由於PID爲10的進程是PID爲5的進程的子進程。遞歸

分析隊列

因爲每一個進程最多隻有一個父進程,但可能有多個子進程,所以進程之間的關係能夠用一棵樹來表示。父進程對應樹中的父節點,而子進程對應樹中的子節點。若是進程[1, 3, 10, 5]的父進程爲[3, 0, 5, 3],那麼這些進程能夠構成以下的一棵樹:如樣例中的樹結構

所以,解決這個問題的第一步是根據輸入的PID和PPID兩個鏈表構建出一個樹。樹是一種特殊的圖(Graph)。圖有兩種經常使用的表示方法,一是基於鄰接表,二是基於鄰接矩陣。因爲樹是一類比較稀疏的圖,通常用鄰接表更爲高效。

用鄰接表來表示一棵樹,咱們能夠把整棵樹存到一個HashMap中。這個HashMap的Key爲進程的PID,Value爲對應進程的全部子進程的PID,也就是樹中對應節點的全部子節點。下面是根據PID和PPID鏈表構建樹的參考代碼:

 1 private Map<Integer, List<Integer>> buildTree(List<Integer> pid, List<Integer> ppid) {
 2     Map<Integer, List<Integer>> processTree = new HashMap<>();
 3     Iterator<Integer> iterator1 = pid.iterator();
 4     Iterator<Integer> iterator2 = ppid.iterator();
 5     while (iterator1.hasNext() && iterator2.hasNext()) {
 6         int p = iterator1.next();
 7         int pp = iterator2.next();
 8         if (!processTree.containsKey(pp)) {
 9             processTree.put(pp, new LinkedList<>());
10         }
11         processTree.get(pp).add(p);
12     }
13     return processTree;
14 }

因爲殺死一個進程會殺死它的全部子進程,那麼對應到樹中,殺死某個節點對應的進程,也就會殺死以該節點爲根節點的子樹中全部節點對應的全部進程。所以,咱們能夠把問題轉化爲:如何遍歷以某節點爲根節點的子樹。

雖然這棵由進程構成的樹不必定是二叉樹(由於節點的子節點數目可能大於2),但遍歷算法大同小異,仍然能夠按照廣度優先或者深度優先的順序遍歷。下面分別介紹兩種方法的代碼。

深度優先解

樹的深度優先搜索的代碼有遞歸和非遞歸兩種寫法。一般基於遞歸的代碼更爲簡潔,深度優先算法須要定義一個遞歸函數用來殺死某個進程,以下面的輔助函數kill。在函數kill中,每當殺死進程target,若是它有子進程,則遞歸調用函數kill去殺死它的每個子進程child。

 1 public List<Integer> killProcess(List<Integer> pid, List<Integer> ppid, int target){
 2     Map<Integer, List<Integer>> processTree = buildTree(pid, ppid);
 3     List<Integer> result = new LinkedList<>();
 4     kill(processTree, target, result);
 5     return result;
 6 }
 7 
 8 private void kill(Map<Integer, List<Integer>> processTree, int target, List<Integer> result) {
 9     result.add(target);
10     if (!processTree.containsKey(target)) {
11         return ;
12     }
13     for (int child : processTree.get(target)) {
14         kill(processTree, child, result);
15     }
16 }

也能夠不構建樹結構直接,利用這兩個數組進行遞歸殺死進程。

 1 public List<Integer> killProcess(List<Integer> pid, List<Integer> ppid, int kill) {
 2         ArrayList<Integer> ans = new ArrayList<Integer>();
 3         ans.add(kill);
 4         for (int i = 0; i < ppid.size(); i++) {
 5             if (ppid.get(i) == kill) {
 6                 ans.addAll(killProcess(pid, ppid, pid.get(i)));
 7             }
 8         }
 9         return ans;
10 }

廣度優先解

基於廣度優先的代碼一般會用到隊列(queue)。咱們首先把第一個待殺死的進程的PID放入隊列中,接下來只要隊列中還有待殺死的進程,就重複執行以下步驟:首先從隊列中去除一個進程,殺死它(即添加到輸出的鏈表中);接着,若是該進程有子進程則把子進程添加到隊列中。

 1 public List<Integer> killProcess(List<Integer> pid, List<Integer> ppid, int target) {
 2     Map<Integer, List<Integer>> processTree = buildTree(pid, ppid));
 3     List<Integer> result = new LinkedList<>();
 4     Queue<Integer> queue = new LinkedList<>();
 5     queue.add(target);
 6     while (!queue.isEmpty()) {
 7         int process = queue.remove();
 8         result.add(process);
 9         if (processTree.containsKey(process)) {
10             for (int child : processTree.get(process)) {
11                 queue.add(child);
12             }
13         }
14     }
15     return result;
16 }
相關文章
相關標籤/搜索