package com.heu.wsq.leetcode.graph;
import java.util.*;
/**
* 1203. 项目管理
* @author wsq
* @date 2021/1/12
* 公司共有 n 个项目和 m 个小组,每个项目要不无人接手,要不就由 m 个小组之一负责。
* group[i] 表示第 i 个项目所属的小组,如果这个项目目前无人接手,那么 group[i] 就等于 -1。(项目和小组都是从零开始编号的)小组可能存在没有接手任何项目的情况。
* 请你帮忙按要求安排这些项目的进度,并返回排序后的项目列表:
* 同一小组的项目,排序后在列表中彼此相邻。
* 项目之间存在一定的依赖关系,我们用一个列表 beforeItems 来表示,其中 beforeItems[i] 表示在进行第 i 个项目前(位于第 i 个项目左侧)应该完成的所有项目。
* 如果存在多个解决方案,只需要返回其中任意一个即可。如果没有合适的解决方案,就请返回一个 空列表 。
*
* 示例 1:
* 输入:n = 8, m = 2, group = [-1,-1,1,0,0,1,0,-1], beforeItems = [[],[6],[5],[6],[3,6],[],[],[]]
* 输出:[6,3,4,1,5,2,0,7]
*
* 链接:https://leetcode-cn.com/problems/sort-items-by-groups-respecting-dependencies
*/
public class SortItems {
public int[] sortItems(int n, int m, int[] group, List<List<Integer>> beforeItems) {
// 1.由于group[i]=-1表示该任务没有被分配小组,影响后续组的拓扑序
// 预处理将group[i]=-1的分配不同的小组编号
int totalM = m;
for (int i = 0; i < group.length; i++){
if (group[i] == -1){
group[i] = totalM;
totalM++;
}
}
// 2.构建项目和组的邻接表
List<Integer>[] groupAdj = new ArrayList[totalM];
List<Integer>[] itemAdj = new ArrayList[n];
for (int i = 0; i < totalM; i++) {
groupAdj[i] = new ArrayList<>();
}
for (int i = 0; i < n; i++){
itemAdj[i] = new ArrayList<>();
}
// 3.建图和统计入度数组
int[] groupsIndegree = new int[totalM];
int[] itemsIndegree = new int[n];
int len = group.length;
for (int i = 0; i < len; i++){
int currGroup = group[i];
List<Integer> befores = beforeItems.get(i);
for (Integer before : befores) {
int beforeGroup = group[before];
if (beforeGroup == currGroup){
itemsIndegree[i]++;
itemAdj[before].add(i);
}else{
groupsIndegree[currGroup]++;
groupAdj[beforeGroup].add(currGroup);
}
}
}
// 4.得到组和项目的拓扑排序结果
List<Integer> groupList = topoSort(groupAdj, groupsIndegree, totalM);
if (groupList.isEmpty()){
return new int[0];
}
List<Integer> itemList = topoSort(itemAdj, itemsIndegree, n);
if (itemList.isEmpty()){
return new int[0];
}
// 5.按照项目的拓扑顺序,保存组与项目的多对一关系,这样做的好处是保留了项目的拓扑顺序
Map<Integer, List<Integer>> group2Items = new HashMap<>();
for (Integer item : itemList) {
group2Items.computeIfAbsent(group[item], key -> new ArrayList<>()).add(item);
}
// 6.根据组的拓扑排序获取最后的结果
List<Integer> res = new ArrayList<>();
for (Integer gp : groupList) {
List<Integer> items = group2Items.getOrDefault(gp, new ArrayList<>());
res.addAll(items);
}
return res.stream().mapToInt(Integer::valueOf).toArray();
}
private List<Integer> topoSort(List<Integer>[] adj, int[] indegree, int n) {
List<Integer> res = new ArrayList<>();
Queue<Integer> queue = new LinkedList<>();
for (int i = 0; i < n; i++){
if (indegree[i] == 0){
queue.offer(i);
}
}
while (!queue.isEmpty()){
Integer front = queue.poll();
res.add(front);
for (Integer successor : adj[front]) {
indegree[successor]--;
if (indegree[successor] == 0){
queue.offer(successor);
}
}
if (res.size() == n){
return res;
}
}
return new ArrayList<>();
}
}
1203. 项目管理(拓扑排序)
最新推荐文章于 2023-05-04 13:28:07 发布
博客围绕Java和图的拓扑排序展开,涉及信息技术领域中后端开发和算法相关内容。Java作为后端开发常用语言,拓扑排序是图算法的重要应用,可解决有向无环图节点排序问题。
607

被折叠的 条评论
为什么被折叠?



