leetcode
leetcode 501 ~ 550
杀掉进程

杀掉进程

难度:

标签:

题目描述

代码结果

运行时间: 59 ms, 内存: 20.4 MB


/*
题目思路:
1. 使用流构建进程树。
2. 使用递归方式杀掉进程及其子进程。
*/
import java.util.*;
import java.util.stream.Collectors;
 
public class KillProcessStream {
    public List<Integer> killProcess(List<Integer> pid, List<Integer> ppid, int kill) {
        Map<Integer, List<Integer>> processTree = ppid.stream().distinct().collect(Collectors.toMap(
            p -> p,
            p -> pid.stream().filter(id -> ppid.get(pid.indexOf(id)).equals(p)).collect(Collectors.toList())
        ));
        List<Integer> result = new ArrayList<>();
        killAllChildren(processTree, kill, result);
        return result;
    }
 
    private void killAllChildren(Map<Integer, List<Integer>> processTree, int kill, List<Integer> result) {
        result.add(kill);
        if (processTree.containsKey(kill)) {
            processTree.get(kill).forEach(child -> killAllChildren(processTree, child, result));
        }
    }
}

解释

方法:

这个题解采用了深度优先搜索(DFS)的方法来解决问题。首先,它建立了一个映射(maps),将每个父进程(ppid)映射到其子进程(pid)列表。然后,从要杀死的进程(kill)开始,使用递归函数process遍历整个进程树,将所有可达的子进程添加到结果列表(self.res)中。

时间复杂度:

O(n)

空间复杂度:

O(n)

代码细节讲解

🦆
如何确保在构建父进程到子进程的映射时,不会遗漏任何进程或者重复添加进程?
在构建映射时,通过遍历整个ppid列表,对每个父进程ID和对应的子进程ID进行映射。使用字典结构确保当多个子进程共享同一父进程时,这些子进程都会被添加到父进程的映射列表中。这种方法通过for循环和字典的键检查(`if parent not in maps`),确保不会遗漏任何子进程,并且每个子进程只被添加一次。这种数据结构的选择避免了重复添加同一个子进程。
🦆
在递归函数`process`中,是否有可能出现栈溢出的情况,如果有,如何预防?
递归函数`process`中确实有可能出现栈溢出的情况,特别是在进程树特别深或形成复杂结构时。为了预防栈溢出,可以考虑使用迭代的深度优先搜索(DFS)代替递归,使用显示的栈来管理待处理的节点。这种方法减少了函数调用栈的使用,从而降低栈溢出的风险。
🦆
如果`kill`指定的进程ID在pid列表中不存在怎么办?题解中似乎没有处理这种情况。
如果`kill`指定的进程ID在pid列表中不存在,按照当前题解的逻辑,结果列表`self.res`将只包含`kill`ID本身,因为没有任何子进程关联到这个不存在的父进程ID。为了更准确地处理这种情况,可以在开始递归之前添加一个检查,确认`kill`ID是否真的存在于pid列表中。如果不存在,可以返回一个空列表或者适当的错误消息。
🦆
题解中的DFS方法是否考虑了进程ID可能不是连续的情况?
题解中使用了字典来映射父进程ID到子进程ID列表,这种方法自然支持非连续的进程ID。字典的键值对映射不依赖于进程ID的连续性,因此无论进程ID是否连续,都能正确地建立和查询父子进程关系。

相关问题