leetcode 1203 项目管理
题目描述
有n
个项目和m
个小组,每个项目会属于0
或1
个小组,每个小组会拥有0
或1
或多个
项目,给定两个数组,一个是group
数组,group[i]
代表了第i
个项目属于哪个小组,如果不归属于任何小组,group[i] = -1
,另一个是beforeItems
数组,beforeItems[i]
表示在进行第i
个项目前(位于第 i
个项目左侧)应该完成的所有项目。
题目要求同一个小组的项目需要紧邻着,若没有合适的解决方案便返回空列表
题目思路
- 将小组和项目分别进行拓扑排序,得到
两个拓扑序
。 - 再将已经排序好的项目,按照各自所在的小组一一加入到一个新建的
HashMap
中,该HashMap
的key
值是小组id
,value
是该小组拥有的项目。这样便得到了每个小组各自的项目的拓扑序
。 - 按照小组的拓扑序,先后加入每个小组的所有的项目,得到
最终的拓扑序
。
题目代码
- 数据预处理,给没有归属于任何一个组的项目编上编号
for(int i = 0; i < n; i++){
if(group[i] == -1){
group[i] = m++;
}
}
- 实例化组和项目的邻接表
List<Integer>[] adjOfGroups = new ArrayList[m];
List<Integer>[] adjOfItems = new ArrayList[n];
for(int i = 0; i < m; i++){
adjOfGroups[i] = new ArrayList<>();
}
for(int i = 0; i < n; i++){
adjOfItems[i] = new ArrayList<>();
}
- 建图,分别统计小组和项目的入度数组
int[] indegreeOfGroups = new int[m];
int[] indegreeOfItems = new int[n];
for(int i = 0; i < n; i++){
int curGroup = group[i];
for(Integer item : beforeItems.get(i)){
int beforeGroup = group[item];
//只有先序和后序项目的小组不同时才需要记录小组的顺序
if(curGroup != beforeGroup){
indegreeOfGroups[curGroup]++;
adjOfGroups[beforeGroup].add(curGroup);
}
}
}
for(int i = 0; i < n; i++){
for(Integer item : beforeItems.get(i)){
indegreeOfItems[i]++;
adjOfItems[item].add(i);
}
}
- 得到组和项目的拓扑排序结果
List<Integer> groupSort = tuboSort(adjOfGroups, indegreeOfGroups, m);
List<Integer> itemSort = tuboSort(adjOfItems, indegreeOfItems, n);
if(groupSort.size() == 0 || itemSort.size() == 0){
return new int[0];
}
//具体的拓扑排序方法
public List<Integer> tuboSort(List<Integer>[] adj, int[] indegree, int num){
Queue<Integer> queue = new LinkedList<>();
for(int i = 0; i < num; i++){
if(indegree[i] == 0){
queue.offer(i);
}
}
List<Integer> res = new ArrayList<>();
while(!queue.isEmpty()){
int top = queue.poll();
res.add(top);
for(Integer a : adj[top]){
indegree[a]--;
if(indegree[a] == 0){
queue.offer(a);
}
}
}
if(res.size() == num){
return res;
}
return new ArrayList<>();
}
- 根据项目的拓扑排序结果,以及项目到组的一对多关系,建立组到项目的一对多关系
Map<Integer, List<Integer>> itemOfGroups = new HashMap<>();
for(Integer item : itemSort){
itemOfGroups.computeIfAbsent(group[item], key -> new ArrayList<>()).add(item);
}//computeIfAbsent方法:如果没有对应的key值,便新建该key值,value则由第二个参数自动计算,该处为新建一个空的ArrayList。
- 把组的拓扑排序结果替换成为项目的拓扑排序结果
List<Integer> res = new ArrayList<>();
for(Integer g : groupSort){
List<Integer> items = itemOfGroups.getOrDefault(g, new ArrayList<>());
//getOrDefault方法:有则get,无则按照括号中给定的参数新建
res.addAll(items);
}
return res.stream().mapToInt(Integer::valueOf).toArray();//List到数组的转换
全部代码
class Solution {
public int[] sortItems(int n, int m, int[] group, List<List<Integer>> beforeItems) {
// 1. 数据预处理,给没有归属于任何一个组的项目编上编号
for(int i = 0; i < n; i++){
if(group[i] == -1){
group[i] = m++;
}
}
// 2. 实例化组和项目的邻接表
List<Integer>[] adjOfGroups = new ArrayList[m];
List<Integer>[] adjOfItems = new ArrayList[n];
for(int i = 0; i < m; i++){
adjOfGroups[i] = new ArrayList<>();
}
for(int i = 0; i < n; i++){
adjOfItems[i] = new ArrayList<>();
}
// 3. 建图,统计入度数组
int[] indegreeOfGroups = new int[m];
int[] indegreeOfItems = new int[n];
for(int i = 0; i < n; i++){
int curGroup = group[i];
for(Integer item : beforeItems.get(i)){
int beforeGroup = group[item];
if(curGroup != beforeGroup){
indegreeOfGroups[curGroup]++;
adjOfGroups[beforeGroup].add(curGroup);
}
}
}
for(int i = 0; i < n; i++){
for(Integer item : beforeItems.get(i)){
indegreeOfItems[i]++;
adjOfItems[item].add(i);
}
}
//可以整合一下
// for(int i = 0; i < n; i++){
// int curGroup = group[i];
// for(Integer item : beforeItems.get(i)){
// indegreeOfItems[i]++;
// adjOfItems[item].add(i);
// int beforeGroup = group[item];
// if(curGroup != beforeGroup){
// indegreeOfGroups[curGroup]++;
// adjOfGroups[beforeGroup].add(curGroup);
// }
// }
// }
// 4. 得到组和项目的拓扑排序结果
List<Integer> groupSort = tuboSort(adjOfGroups, indegreeOfGroups, m);
List<Integer> itemSort = tuboSort(adjOfItems, indegreeOfItems, n);
if(groupSort.size() == 0 || itemSort.size() == 0){
return new int[0];
}
// 5. 根据项目的拓扑排序结果,以及项目到组的一对多关系,建立组到项目的一对多关系
Map<Integer, List<Integer>> itemOfGroups = new HashMap<>();
for(Integer item : itemSort){
itemOfGroups.computeIfAbsent(group[item], key -> new ArrayList<>()).add(item);
}
// 6. 把组的拓扑排序结果替换成为项目的拓扑排序结果
List<Integer> res = new ArrayList<>();
for(Integer g : groupSort){
List<Integer> items = itemOfGroups.getOrDefault(g, new ArrayList<>());
res.addAll(items);
}
return res.stream().mapToInt(Integer::valueOf).toArray();
}
public List<Integer> tuboSort(List<Integer>[] adj, int[] indegree, int num){
Queue<Integer> queue = new LinkedList<>();
for(int i = 0; i < num; i++){
if(indegree[i] == 0){
queue.offer(i);
}
}
List<Integer> res = new ArrayList<>();
while(!queue.isEmpty()){
int top = queue.poll();
res.add(top);
for(Integer a : adj[top]){
indegree[a]--;
if(indegree[a] == 0){
queue.offer(a);
}
}
}
if(res.size() == num){
return res;
}
return new ArrayList<>();
}
}