题目
https://leetcode-cn.com/problems/sort-items-by-groups-respecting-dependencies/
拓扑排序
每个项目之间存在执行的先后顺序,因此可以对项目拓扑排序得到一个列表。 项目与组是一对多的关系也可以对组进行一个拓扑排序的到组的先后顺序。由项目的拓扑排序可以得到组与项目的一对多的关系,将组的拓扑排序替换为项目的拓扑排序即可得到结果。
class Solution {
public int[] sortItems(int n, int m, int[] group, List<List<Integer>> beforeItems) {
// 第一步:给没有承接任何项目的小组上一个编号
for (int i = 0; i < group.length; i++) {
if (group[i] == -1) {
group[i] = m++;
}
}
// 第二步: 实例化组和项目的邻接表
List<Integer>[] groupAdj = new ArrayList[m];
List<Integer>[] itemAdj = new ArrayList[n];
for (int i = 0; i < m; i++) groupAdj[i] = new ArrayList<>();
for (int i = 0; i < n; i++) itemAdj[i] = new ArrayList<>();
// 第三步: 建图并统计入读数组
int[] groupsIndegree = new int[m];
int[] itemsIndegree = new int[n];
int len = group.length;
for (int i = 0; i < len; i++) {
int currentGroup = group[i];
for (Integer item : beforeItems.get(i)) {
int beforeGroup = group[item];
if (beforeGroup != currentGroup) {
groupAdj[beforeGroup].add(currentGroup);
groupsIndegree[currentGroup]++;
}
}
}
for (int i = 0; i < len; i++) {
for (Integer item : beforeItems.get(i)) {
itemAdj[item].add(i);
itemsIndegree[i]++;
}
}
// 第四步: 得到组和项目的拓扑结果
List<Integer> groupList = topologicalSort(groupAdj, groupsIndegree, m);
if (groupList.size() == 0) {
return new int[0];
}
List<Integer> itemList = topologicalSort(itemAdj, itemsIndegree, n);
if (itemList.size() == 0) {
return new int[0];
}
// 第五步: 根据项目的拓扑排序结果,简历组到项目的1对多关系
Map<Integer, List<Integer>> groups2Items = new HashMap<>();
for (Integer item : itemList) {
groups2Items.computeIfAbsent(group[item], k -> new ArrayList<>()).add(item);
}
// 第六步: 把组的拓扑排序结果替换成项目的拓扑排序结果
List<Integer> res = new ArrayList<>();
for (Integer groupId : groupList) {
List<Integer> items = groups2Items.getOrDefault(groupId, new ArrayList<>());
res.addAll(items);
}
return res.stream().mapToInt(Integer::valueOf).toArray();
}
private List<Integer> topologicalSort(List<Integer>[] adj, int[] indegree, int n) {
List<Integer> res = new ArrayList<>();
Queue<Integer> queue = new ArrayDeque<>();
for (int i = 0; i < n; i++) {
if (indegree[i] == 0) {
queue.offer(i);
}
}
while (!queue.isEmpty()) {
int front = queue.poll();
res.add(front);
for (int successor : adj[front]) {
indegree[successor]--;
if (indegree[successor] == 0) {
queue.offer(successor);
}
}
}
if (res.size() != n)
return new ArrayList<>();
return res;
}
}