Open azl397985856 opened 2 years ago
不会做,太难了
class Solution:
def topological_sort(self, graph, node, seen):
result = []
def recursive_helper(node):
for neighbor in graph[node]:
if neighbor not in seen:
seen.add(neighbor)
recursive_helper(neighbor)
result.insert(0, node)
recursive_helper(node)
return result
def sortItems(self, n: int, m: int, group: List[int],
beforeItems: List[List[int]]) -> List[int]:
group_items_map = defaultdict(list)
for i in range(n):
if group[i] == -1:
group[i] = m
m += 1
group_items_map[group[i]].append(i)
graph_group = defaultdict(set)
graph_item = {i: defaultdict(list) for i in range(m)}
for item_after, before_items in enumerate(beforeItems):
for item_before in before_items:
group_before = group[item_before]
group_after = group[item_after]
if group_before != group_after:
graph_group[group_before].add(group_after)
else:
graph_item[group_before][item_before].append(item_after)
group_order = []
seen = set()
for group_id in range(m):
if group_id not in seen:
seen.add(group_id)
group_order += self.topological_sort(graph_group, group_id, seen)
final_result = []
for group_id in group_order:
seen = set()
for item_id in group_items_map[group_id]:
if item_id not in seen:
seen.add(item_id)
final_result += self.topological_sort(graph_item[group_id], item_id, seen)
return final_result
Time: O(V+E)
Space: O(V+E)
/**
* @param {number} n
* @param {number} m
* @param {number[]} group
* @param {number[][]} beforeItems
* @return {number[]}
*/
const sortItems = function(n, m, group, beforeItems) {
const groupToItems = new Map();
let groupSize = m;
for (let i = 0; i < n; i++) {
if (group[i] === -1) group[i] = groupSize++; // assign new group to each ungrouped item
if (!groupToItems.has(group[i])) groupToItems.set(group[i], []);
groupToItems.get(group[i]).push(i);
}
const groupIn = Array(groupSize).fill(0); // in degree for each group
const groupAdj = Array.from({length: groupSize}, () => new Set()); // adj list for each group
const itemIn = Array(n).fill(0); // in degree for each item within same group
const itemAdj = Array.from({length: n}, () => new Set()); // adj list for each item within same group
for (let toIdx = 0; toIdx < beforeItems.length; toIdx++) {
const toGroup = group[toIdx];
for (const fromIdx of beforeItems[toIdx]) {
const fromGroup = group[fromIdx];
if (toGroup === fromGroup) {
itemAdj[fromIdx].add(toIdx);
itemIn[toIdx] += 1;
} else if (!groupAdj[fromGroup].has(toGroup)) {
groupAdj[fromGroup].add(toGroup);
groupIn[toGroup] += 1;
}
}
}
// Verify group order
const queue = [];
const sortedGroup = [];
for (let i = 0; i < groupSize; i++) {
if (groupIn[i] === 0) {
queue.push(i);
sortedGroup.push(i);
}
}
while (queue.length > 0) {
const curr = queue.shift();
for (const next of groupAdj[curr]) {
if (--groupIn[next] === 0) {
queue.push(next);
sortedGroup.push(next);
}
}
}
if (sortedGroup.length !== groupSize) return []; // invalid
// Verify item order
const ans = [];
for (const groupId of sortedGroup) {
const items = groupToItems.get(groupId) || [];
const queue = [];
let count = 0;
for (const item of items) {
if (itemIn[item] === 0) {
queue.push(item);
ans.push(item);
count += 1;
}
}
while (queue.length > 0) {
const curr = queue.shift();
for (const next of itemAdj[curr]) {
if (--itemIn[next] === 0) {
queue.push(next);
ans.push(next);
count += 1;
}
}
}
if (count !== items.length) return []; // invalid
}
return ans;
};
占坑打卡
const topSort = (deg, graph, items) => {
const Q = [];
for (const item of items) {
if (deg[item] === 0) {
Q.push(item);
}
}
const res = [];
while (Q.length) {
const u = Q.shift();
res.push(u);
for (let i = 0; i < graph[u].length; ++i) {
const v = graph[u][i];
if (--deg[v] === 0) {
Q.push(v);
}
}
}
return res.length == items.length ? res : [];
}
var sortItems = function(n, m, group, beforeItems) {
const groupItem = new Array(n + m).fill(0).map(() => []);
// 组间和组内依赖图
const groupGraph = new Array(n + m).fill(0).map(() => []);
const itemGraph = new Array(n).fill(0).map(() => []);
// 组间和组内入度数组
const groupDegree = new Array(n + m).fill(0);
const itemDegree = new Array(n).fill(0);
const id = new Array(n + m).fill(0).map((v, index) => index);
let leftId = m;
// 给未分配的 item 分配一个 groupId
for (let i = 0; i < n; ++i) {
if (group[i] === -1) {
group[i] = leftId;
leftId += 1;
}
groupItem[group[i]].push(i);
}
// 依赖关系建图
for (let i = 0; i < n; ++i) {
const curGroupId = group[i];
for (const item of beforeItems[i]) {
const beforeGroupId = group[item];
if (beforeGroupId === curGroupId) {
itemDegree[i] += 1;
itemGraph[item].push(i);
} else {
groupDegree[curGroupId] += 1;
groupGraph[beforeGroupId].push(curGroupId);
}
}
}
// 组间拓扑关系排序
const groupTopSort = topSort(groupDegree, groupGraph, id);
if (groupTopSort.length == 0) {
return [];
}
const ans = [];
// 组内拓扑关系排序
for (const curGroupId of groupTopSort) {
const size = groupItem[curGroupId].length;
if (size == 0) {
continue;
}
const res = topSort(itemDegree, itemGraph, groupItem[curGroupId]);
if (res.length === 0) {
return [];
}
for (const item of res) {
ans.push(item);
}
}
return ans;
};
参考答案
class Solution:
def tp_sort(self, items, indegree, neighbors):
q = []
order = []
for item in items:
if not indegree[item]:
q.append(item)
while q:
cur = q.pop(0)
order.append(cur)
for neighbor in neighbors[cur]:
indegree[neighbor] -= 1
if not indegree[neighbor]:
q.append(neighbor)
return order
def sortItems(self, n: int, m: int, group: List[int], pres: List[List[int]]) -> List[int]:
for project in range(n):
if group[project] == -1:
group[project] = m
m += 1
project_indegree = collections.defaultdict(int)
group_indegree = collections.defaultdict(int)
project_neighbors = collections.defaultdict(list)
group_neighbors = collections.defaultdict(list)
group_projects = collections.defaultdict(list)
for project in range(n):
group_projects[group[project]].append(project)
for pre in pres[project]:
if group[pre] != group[project]:
group_indegree[group[project]] += 1
group_neighbors[group[pre]].append(group[project])
else:
project_indegree[project] += 1
project_neighbors[pre].append(project)
group_queue = self.tp_sort([i for i in range(m)], group_indegree, group_neighbors)
if len(group_queue) != m:
return []
ans = []
for group_id in group_queue:
project_queue = self.tp_sort(group_projects[group_id], project_indegree, project_neighbors)
if len(project_queue) != len(group_projects[group_id]):
return []
ans += project_queue
return ans
贴上大神做法: https://www.youtube.com/watch?v=I4Vwkq7e2xE
之所以需要两次拓扑排序是因为 3 -> 5, 3->2 单次拓扑排序, 5,2 的顺序是可以swap的,但是这道题规定了也必须按组sort, 如果2,3 在group1, 5在group 2,那必须先完成3,2 再完成5.
大神新思路可以添加'dummy node',插入每一个group之间,这样保证3->5 这一行会变成3->dummy tail -> 5,这样只需要单次topology sort 就可以了。
class Solution:
def topsort(self,queue,out_edges,in_degrees):
ordering = []
while queue:
node = queue.popleft()
ordering.append(node)
for next_ in out_edges[node]:
in_degrees[next_] -= 1
if not in_degrees[next_]:
queue.append(next_)
return ordering
def sortItems(self, n: int, m: int, group: List[int], beforeItems: List[List[int]]) -> List[int]:
# create dummy head, dummy tail
# group: -1 可以随便摆,不用按组顺序摆
heads = [n + 2 * i for i in range(m)]
tails = [n + 2 * i + 1 for i in range(m)]
nodes = list(range(n + 2 * m)) # node + dummy.head, dummy.tail
out_edges = collections.defaultdict(list)
in_degrees = collections.defaultdict(int)
for item, (g,b) in enumerate(zip(group, beforeItems)):
if g != -1:
head,tail = heads[g],tails[g]
out_edges[head].append(item)
in_degrees[item] += 1
out_edges[item].append(tail)
in_degrees[tail] += 1
# 这一步把每个group 中单独的item 连上head -> item -> tail
for before in b:
# from which group, to which group, 连接group
from_,to_ = group[before],group[item]
same_group = True if from_ == to_ else False
# 这里要找到group, from 的group,也就是before的group.tail 连接到to_,item group.head
out_ = before if same_group or from_ == -1 else tails[from_]
to_ = item if same_group or to_ == -1 else heads[to_]
out_edges[out_].append(to_)
in_degrees[to_] += 1
# apply topological sort
# first find the node, in_degree = 0
starts =[node for node in nodes if not in_degrees[node]]
order = []
for start in starts:
order += self.topsort(collections.deque([start]),out_edges,in_degrees)
#remember to remove dummy node
order = [node for node in order if node < n]
# 如果有环,那么in_degrees[有环的任意点] 不可能为0,直接不执行
return order if len(order) == n else []
Time complexity: O((n+M)2)
Space complexity: O(n+M)2)
class Solution {
public int[] sortItems(int n, int m, int[] group, List<List<Integer>> beforeItems) {
Map<Integer, Integer> indegreeMap = new HashMap();
Map<Integer, List<Integer>> graph = new HashMap<>();
Map<Integer, List<Integer>> groupMap = new HashMap<>();
Map<Integer, Integer> grpIndegreeMap = new HashMap();
Map<Integer, List<Integer>> grpGraph = new HashMap<>();
for (int i = 0; i < n; i++) {
indegreeMap.put(i, 0);
graph.put(i, new ArrayList<>());
}
int nextGrpId = m;
for (int i = 0; i < group.length; i++) {
if (group[i] == -1) {
group[i] = nextGrpId;
nextGrpId++;
}
if (groupMap.get(group[i]) == null) {
groupMap.put(group[i], new ArrayList<>());
}
groupMap.get(group[i]).add(i);
}
for (int i = 0; i < n; i++) {
List<Integer> beforeList = beforeItems.get(i);
if (beforeList != null) {
for (Integer id : beforeList) {
if (group[i] == group[id]) {
indegreeMap.put(i, indegreeMap.get(i) + 1);
graph.get(id).add(i);
}
}
}
}
Map<Integer, List<Integer>> sortedGroupItemMap = new HashMap<>();
for (int grpId : groupMap.keySet()) {
List<Integer> sortedGroupItem = topoLogicSort(groupMap.get(grpId), indegreeMap, graph);
if (sortedGroupItem.size() == 0) {
return new int[0];
}
sortedGroupItemMap.put(grpId, sortedGroupItem);
}
for (int grpId : group) {
grpIndegreeMap.put(grpId, 0);
}
for (int i = 0; i < n; i++) {
List<Integer> beforeList = beforeItems.get(i);
if (beforeList != null) {
for (Integer id : beforeList) {
if (group[i] != group[id]) {
grpIndegreeMap.put(group[i], grpIndegreeMap.getOrDefault(group[i], 0) + 1);
if (grpGraph.get(group[id]) == null) {
grpGraph.put(group[id], new ArrayList<>());
}
grpGraph.get(group[id]).add(group[i]);
}
}
}
}
List<Integer> grpIDs = new ArrayList<>(grpIndegreeMap.keySet());
List<Integer> sortedGrp = topoLogicSort(grpIDs, grpIndegreeMap, grpGraph);
List<Integer> tempList = new ArrayList<>();
for (int grpId : sortedGrp) {
tempList.addAll(sortedGroupItemMap.get(grpId));
}
int[] res = new int[tempList.size()];
for (int i = 0; i < tempList.size(); i++) {
res[i] = tempList.get(i);
}
return res;
}
private List<Integer> topoLogicSort(List<Integer> items, Map<Integer, Integer> indegreeMap, Map<Integer, List<Integer>> graph) {
Queue<Integer> q = new LinkedList<>();
for (int id : items) {
if (indegreeMap.get(id) == 0) {
q.add(id);
}
}
List<Integer> tempList = new ArrayList<>();
while (!q.isEmpty()) {
int curId = q.poll();
tempList.add(curId);
List<Integer> nextIDs = graph.get(curId);
if (nextIDs != null) {
for (Integer nextID : nextIDs) {
indegreeMap.put(nextID, indegreeMap.get(nextID) - 1);
if (indegreeMap.get(nextID) == 0) {
q.add(nextID);
}
}
}
}
if (tempList.size() != items.size()) {
return new ArrayList<>();
}
return tempList;
}
}
能看懂就是大胜利
public int[] sortItems(int n, int m, int[] group, List<List<Integer>> beforeItems) {
List<List<Integer>> groupItem = new ArrayList<>();//项目分组
for(int i = 0;i < n + m;i++){//初始化小组
groupItem.add(new ArrayList<>());
}
int gId = m;//新的组号从m开始
for(int i = 0;i < group.length;i++){
if(group[i] == -1)group[i] = gId++;//没有id的加上组id
groupItem.get(group[i]).add(i);//同一组的放在一起
}
List<List<Integer>> graphInGroup = new ArrayList<>();//组内拓扑关系
List<List<Integer>> graphOutGroup = new ArrayList<>();//组间拓扑关系
for(int i = 0;i < n + m;i++){//初始化拓扑关系
graphOutGroup.add(new ArrayList<>());
if(i >= n)continue;
graphInGroup.add(new ArrayList<>());
}
List<Integer> groupId = new ArrayList<>();//所有组id
for(int i = 0;i < n + m;i++){
groupId.add(i);
}
// 需要拓扑排序 所以结点的入度必不可少 两个数组分别维护不同结点的入度
int[] degInGroup = new int[n];//组内 结点入度 (组内项目入度)
int[] degOutGroup = new int[n + m];//组间 结点入度(小组入度)
for(int i = 0;i < beforeItems.size();i++){//遍历关系
int curGroupId = group[i];//当前项目i所属的小组id
List<Integer> beforeItem = beforeItems.get(i);
for(Integer item : beforeItem){
if(group[item] == curGroupId){//同一组 修改组内拓扑
degInGroup[i]++;// 组内结点的入度+1
graphInGroup.get(item).add(i);//item 在 i之前
}else{
degOutGroup[curGroupId]++;// 小组间的结点入度 + 1
graphOutGroup.get(group[item]).add(curGroupId);// group[item] 小组 在 curGroupId 之前
}
}
}
//组间拓扑排序,也就是小组之间的拓扑排序,需要的参数 小组结点的入度degOutGroup,所有的小组groupId,组间的拓扑关系图graphOutGroup
List<Integer> outGroupTopSort = topSort(degOutGroup,groupId,graphOutGroup);
if(outGroupTopSort.size() == 0)return new int[0];//无法拓扑排序 返回
int[] res = new int[n];
int index = 0;
for(Integer gid : outGroupTopSort){//遍历排序后的小组id
List<Integer> items = groupItem.get(gid);//根据小组id 拿到这一小组中的所有成员
if(items.size() == 0)continue;
//组内拓扑排序,需要的参数 组内结点的入度degInGroup,组内的所有的结点groupItem.get(gid),组内的拓扑关系图graphInGroup
List<Integer> inGourpTopSort = topSort(degInGroup,groupItem.get(gid),graphInGroup);
if(inGourpTopSort.size() == 0)return new int[0];//无法拓扑排序 返回
for(int item : inGourpTopSort){//排序后,依次的放入答案集合当中
res[index++] = item;
}
}
return res;
}
public List<Integer> topSort(int[] deg, List<Integer> items,List<List<Integer>> graph){
Queue<Integer> queue = new LinkedList<>();
for(Integer item:items){
if(deg[item] == 0)queue.offer(item);
}
List<Integer> res = new ArrayList<>();
while(!queue.isEmpty()){
int cur = queue.poll();
res.add(cur);
for(int neighbor: graph.get(cur)){
if(--deg[neighbor] == 0){
queue.offer(neighbor);
}
}
}
return res.size() == items.size() ? res : new ArrayList<>();
}
不是很懂,先打卡再学 2次拓扑排序
class Solution {
public int[] sortItems(int n, int m, int[] group, List<List<Integer>> beforeItems) {
Map<Integer, Integer> indegreeMap = new HashMap();
Map<Integer, List<Integer>> graph = new HashMap<>();
Map<Integer, List<Integer>> groupMap = new HashMap<>();
Map<Integer, Integer> grpIndegreeMap = new HashMap();
Map<Integer, List<Integer>> grpGraph = new HashMap<>();
for (int i = 0; i < n; i++) {
indegreeMap.put(i, 0);
graph.put(i, new ArrayList<>());
}
int nextGrpId = m;
for (int i = 0; i < group.length; i++) {
if (group[i] == -1) {
group[i] = nextGrpId;
nextGrpId++;
}
if (groupMap.get(group[i]) == null) {
groupMap.put(group[i], new ArrayList<>());
}
groupMap.get(group[i]).add(i);
}
for (int i = 0; i < n; i++) {
List<Integer> beforeList = beforeItems.get(i);
if (beforeList != null) {
for (Integer id : beforeList) {
if (group[i] == group[id]) {
indegreeMap.put(i, indegreeMap.get(i) + 1);
graph.get(id).add(i);
}
}
}
}
Map<Integer, List<Integer>> sortedGroupItemMap = new HashMap<>();
for (int grpId : groupMap.keySet()) {
List<Integer> sortedGroupItem = topoLogicSort(groupMap.get(grpId), indegreeMap, graph);
if (sortedGroupItem.size() == 0) {
return new int[0];
}
sortedGroupItemMap.put(grpId, sortedGroupItem);
}
for (int grpId : group) {
grpIndegreeMap.put(grpId, 0);
}
for (int i = 0; i < n; i++) {
List<Integer> beforeList = beforeItems.get(i);
if (beforeList != null) {
for (Integer id : beforeList) {
if (group[i] != group[id]) {
grpIndegreeMap.put(group[i], grpIndegreeMap.getOrDefault(group[i], 0) + 1);
if (grpGraph.get(group[id]) == null) {
grpGraph.put(group[id], new ArrayList<>());
}
grpGraph.get(group[id]).add(group[i]);
}
}
}
}
List<Integer> grpIDs = new ArrayList<>(grpIndegreeMap.keySet());
List<Integer> sortedGrp = topoLogicSort(grpIDs, grpIndegreeMap, grpGraph);
List<Integer> tempList = new ArrayList<>();
for (int grpId : sortedGrp) {
tempList.addAll(sortedGroupItemMap.get(grpId));
}
int[] res = new int[tempList.size()];
for (int i = 0; i < tempList.size(); i++) {
res[i] = tempList.get(i);
}
return res;
}
private List<Integer> topoLogicSort(List<Integer> items, Map<Integer, Integer> indegreeMap, Map<Integer, List<Integer>> graph) {
Queue<Integer> q = new LinkedList<>();
for (int id : items) {
if (indegreeMap.get(id) == 0) {
q.add(id);
}
}
List<Integer> tempList = new ArrayList<>();
while (!q.isEmpty()) {
int curId = q.poll();
tempList.add(curId);
List<Integer> nextIDs = graph.get(curId);
if (nextIDs != null) {
for (Integer nextID : nextIDs) {
indegreeMap.put(nextID, indegreeMap.get(nextID) - 1);
if (indegreeMap.get(nextID) == 0) {
q.add(nextID);
}
}
}
}
if (tempList.size() != items.size()) {
return new ArrayList<>();
}
return tempList;
}
}
时间复杂度 O(n)
空间复杂度 O(n)
参考官方解析(太🚹了)
class Solution:
def tp_sort(self, items, indegree, neighbors):
q = collections.deque([])
ans = []
for item in items:
if not indegree[item]:
q.append(item)
while q:
cur = q.popleft()
ans.append(cur)
for neighbor in neighbors[cur]:
indegree[neighbor] -= 1
if not indegree[neighbor]:
q.append(neighbor)
return ans
def sortItems(self, n: int, m: int, group: List[int], pres: List[List[int]]) -> List[int]:
max_group_id = m
for project in range(n):
if group[project] == -1:
group[project] = max_group_id
max_group_id += 1
project_indegree = collections.defaultdict(int)
group_indegree = collections.defaultdict(int)
project_neighbors = collections.defaultdict(list)
group_neighbors = collections.defaultdict(list)
group_projects = collections.defaultdict(list)
for project in range(n):
group_projects[group[project]].append(project)
for pre in pres[project]:
if group[pre] != group[project]:
# 小组关系图
group_indegree[group[project]] += 1
group_neighbors[group[pre]].append(group[project])
else:
# 项目关系图
project_indegree[project] += 1
project_neighbors[pre].append(project)
ans = []
group_queue = self.tp_sort([i for i in range(max_group_id)], group_indegree, group_neighbors)
if len(group_queue) != max_group_id:
return []
for group_id in group_queue:
project_queue = self.tp_sort(group_projects[group_id], project_indegree, project_neighbors)
if len(project_queue) != len(group_projects[group_id]):
return []
ans += project_queue
return ans
Referring to the solution. Do one topological sort on the groups, then do another topological sort on the projects taken by each groups.
class Solution:
def sortItems(self, n: int, m: int, group: List[int], beforeItems: List[List[int]]) -> List[int]:
max_gid = m
for p in range(n):
if group[p] == -1:
group[p] = max_gid
max_gid += 1
project_indegree = collections.defaultdict(int)
group_indegree = collections.defaultdict(int)
project_neighbors = collections.defaultdict(list)
group_neighbors = collections.defaultdict(list)
group_projects = collections.defaultdict(list)
for project in range(n):
group_projects[group[project]].append(project)
for before in beforeItems[project]:
if group[before] != group[project]:
group_indegree[group[project]] += 1
group_neighbors[group[before]].append(group[project])
else:
project_indegree[project] += 1
project_neighbors[before].append(project)
ans = []
group_queue = self.topo_sort([i for i in range(max_gid)], group_indegree, group_neighbors)
if len(group_queue) != max_gid:
return []
for group_id in group_queue:
project_queue = self.topo_sort(group_projects[group_id], project_indegree, project_neighbors)
if len(project_queue) != len(group_projects[group_id]):
return []
ans += project_queue
return ans
def topo_sort(self, lst, indegree, neighbors):
queue = collections.deque([])
ans = []
for i in lst:
if not indegree[i]:
queue.append(i)
while queue:
cur = queue.popleft()
ans.append(cur)
for neighbor in neighbors[cur]:
indegree[neighbor] -= 1
if not indegree[neighbor]:
queue.append(neighbor)
return ans
Time complexity: O(V+E). Space complexity: O(V+E)
两次拓扑
class Solution:
def sortItems(self, n: int, m: int, group: List[int], beforeItems: List[List[int]]) -> List[int]:
def topo(graph,degree,num):
res=[]
stk=[]
for i in range(num):
if degree[i]==0:
stk.append(i)
while len(stk)>0:
m=len(stk)
for i in range(m):
p=stk.pop(0)
res.append(p)
for j in graph[p]:
degree[j]-=1
if degree[j]==0:
stk.append(j)
if len(res)==num:
return res
return []
g=m
for i in range(n):
if group[i]==-1:
group[i]=g
g+=1
groupgraph=[[] for i in range(g)]
groupdegree=[0]*g
itemgraph=[[] for i in range(n)]
itemdegree=[0]*n
for i in range(n):
if len(beforeItems[i])>0:
for j in beforeItems[i]:
if group[j]!=group[i]:
groupgraph[group[j]].append(group[i])
groupdegree[group[i]]+=1
itemgraph[j].append(i)
itemdegree[i]+=1
grp=topo(groupgraph,groupdegree,g)
itm=topo(itemgraph,itemdegree,n)
if len(grp)==0 or len(itm)==0:
return []
grp2itm=defaultdict(list)
for i in range(n):
idx=itm[i]
gp=group[idx]
grp2itm[gp].append(idx)
res=[]
for i in grp:
res+=grp2itm[i]
if len(res)==n:
return res
else:
return []
时间复杂度:O(m+n) 空间复杂度:O(m+n)
copy官方 (先打开,在学习)
class Solution:
def tp_sort(self, items, indegree, neighbors):
q = collections.deque([])
ans = []
for item in items:
if not indegree[item]:
q.append(item)
while q:
cur = q.popleft()
ans.append(cur)
for neighbor in neighbors[cur]:
indegree[neighbor] -= 1
if not indegree[neighbor]:
q.append(neighbor)
return ans
def sortItems(self, n: int, m: int, group: List[int], pres: List[List[int]]) -> List[int]:
max_group_id = m
for project in range(n):
if group[project] == -1:
group[project] = max_group_id
max_group_id += 1
project_indegree = collections.defaultdict(int)
group_indegree = collections.defaultdict(int)
project_neighbors = collections.defaultdict(list)
group_neighbors = collections.defaultdict(list)
group_projects = collections.defaultdict(list)
for project in range(n):
group_projects[group[project]].append(project)
for pre in pres[project]:
if group[pre] != group[project]:
# 小组关系图
group_indegree[group[project]] += 1
group_neighbors[group[pre]].append(group[project])
else:
# 项目关系图
project_indegree[project] += 1
project_neighbors[pre].append(project)
ans = []
group_queue = self.tp_sort([i for i in range(max_group_id)], group_indegree, group_neighbors)
if len(group_queue) != max_group_id:
return []
for group_id in group_queue:
project_queue = self.tp_sort(group_projects[group_id], project_indegree, project_neighbors)
if len(project_queue) != len(group_projects[group_id]):
return []
ans += project_queue
return ans
class Solution {
public int[] sortItems(int n, int m, int[] group, List<List<Integer>> beforeItems) {
List<List<Integer>> groupItem = new ArrayList<>();
for (int i = 0; i < n + m; ++i) {
groupItem.add(new ArrayList<>());
}
List<List<Integer>> groupGraph = new ArrayList<>();
for (int i = 0; i < n + m; ++i) {
groupGraph.add(new ArrayList<>());
}
List<List<Integer>> itemGraph = new ArrayList<>();
for (int i = 0; i < n; ++i) {
itemGraph.add(new ArrayList<>());
}
int[] groupDegree = new int[n + m];
int[] itemDegree = new int[n];
List<Integer> id = new ArrayList<>();
for (int i = 0; i < n + m; ++i) {
id.add(i);
}
int leftId = m;
for (int i = 0; i < n; ++i) {
if (group[i] == -1) {
group[i] = leftId;
leftId += 1;
}
groupItem.get(group[i]).add(i);
}
// 依赖关系建图
for (int i = 0; i < n; ++i) {
int curGroupId = group[i];
for (int item : beforeItems.get(i)) {
int beforeGroupId = group[item];
if (beforeGroupId == curGroupId) {
itemDegree[i] += 1;
itemGraph.get(item).add(i);
} else {
groupDegree[curGroupId] += 1;
groupGraph.get(beforeGroupId).add(curGroupId);
}
}
}
List<Integer> groupTopSort = topSort(groupDegree, groupGraph, id);
if (groupTopSort.size() == 0) {
return new int[0];
}
int[] ans = new int[n];
int index = 0;
for (int curGroupId : groupTopSort) {
int size = groupItem.get(curGroupId).size();
if (size == 0) {
continue;
}
List<Integer> res = topSort(itemDegree, itemGraph, groupItem.get(curGroupId));
if (res.size() == 0) {
return new int[0];
}
for (int item : res) {
ans[index++] = item;
}
}
return ans;
}
public List<Integer> topSort(int[] deg, List<List<Integer>> graph, List<Integer> items) {
Queue<Integer> queue = new LinkedList<>();
for (int item : items) {
if (deg[item] == 0) {
queue.offer(item);
}
}
List<Integer> res = new ArrayList<>();
while (!queue.isEmpty()) {
int u = queue.poll();
res.add(u);
for (int v : graph.get(u)) {
if (--deg[v] == 0) {
queue.offer(v);
}
}
}
return res.size() == items.size() ? res : new ArrayList<Integer>();
}
}
先打卡
var sortItems = function(n, m, group, beforeItems) {
const grahG = [], degG = new Uint16Array(n + m), idsG = [],
grahI = [], degI = new Uint16Array(n), idsI = [], r = []
for (let i = 0; i < n; i++) {
if (group[i] === -1) {
idsG[m] = m // 从组数起分配,避免重复
group[i] = m++
} else idsG[group[i]] = group[i]
if (!idsI[group[i]]) idsI[group[i]] = [] // 同组项目,放入到一起
idsI[group[i]].push(i)
}
for (let i = 0; i < n; i++) {
for (let j = 0; j < beforeItems[i].length; j++) {
const itemI = beforeItems[i][j]
if (group[i] === group[itemI]) {// 同组,收集 项目 依赖
degI[i]++
if (!grahI[itemI]) grahI[itemI] = []
grahI[itemI].push(i)
} else {// 不同组,收集 组 依赖
degG[group[i]]++
if (!grahG[group[itemI]]) grahG[group[itemI]] = []
grahG[group[itemI]].push(group[i])
}
}
}
const idsGS = sort(idsG.filter(v => v !== void 0), grahG, degG) // 组排序
if (idsGS.length === 0) return []
for (let i = 0; i < idsGS.length; i++) {// 组有序,组内项目排序
if (!idsI[idsGS[i]]) continue
const idsIS = sort(idsI[idsGS[i]], grahI, degI)
if (idsIS.length === 0) return []
r.push(...idsIS)
}
return r
};
const sort = (ids, grah, deg) => {// 拓扑排序:id列表,图,入度
const q = [], r = []
let start = 0
for (let i = 0; i < ids.length; i++) if (deg[ids[i]] === 0) q.push(ids[i])
while (start < q.length) {
const n = q[start++]
r.push(n)
if (!grah[n]) continue
for (let i = 0; i < grah[n].length; i++) if (--deg[grah[n][i]] === 0) q.push(grah[n][i])
}
return r.length === ids.length ? r : []
}
Go Code:
func topSort(graph [][]int, deg, items []int) (orders []int) {
var q []int
for _, i := range items {
if deg[i] == 0 {
q = append(q, i)
}
}
for len(q) > 0 {
from := q[0]
q = q[1:]
orders = append(orders, from)
for _, to := range graph[from] {
deg[to]--
if deg[to] == 0 {
q = append(q, to)
}
}
}
return
}
func sortItems(n, m int, group []int, beforeItems [][]int) (ans []int) {
groupItems := make([][]int, m+n)
for i := range group {
if group[i] == -1 {
group[i] = m + i
}
groupItems[group[i]] = append(groupItems[group[i]], i)
}
groupGraph := make([][]int, m+n)
groupDegree := make([]int, m+n)
itemGraph := make([][]int, n)
itemDegree := make([]int, n)
for cur, items := range beforeItems {
curGroupID := group[cur]
for _, pre := range items {
preGroupID := group[pre]
if preGroupID != curGroupID {
groupGraph[preGroupID] = append(groupGraph[preGroupID], curGroupID)
groupDegree[curGroupID]++
} else {
itemGraph[pre] = append(itemGraph[pre], cur)
itemDegree[cur]++
}
}
}
items := make([]int, m+n)
for i := range items {
items[i] = i
}
groupOrders := topSort(groupGraph, groupDegree, items)
if len(groupOrders) < len(items) {
return nil
}
for _, groupID := range groupOrders {
items := groupItems[groupID]
orders := topSort(itemGraph, itemDegree, items)
if len(orders) < len(items) {
return nil
}
ans = append(ans, orders...)
}
return
}
复杂度分析
令 n 为数组长度。
思路:图 拓扑排序 学习别人的题解 整理下思路会发现全部需要的结构为一个 组表、一个组依赖表、一项目依赖表、组依赖数量表、项目依赖数量表 各个表的建立目的: 组表:为了记录每个组都有哪些项目; 组依赖表:为了记录都有哪些组依赖了这个组; 项目依赖表:为了记录都有哪些项目依赖了这个项目; 组依赖数量表: 为了找到哪个组可以第一个开始(即没有依赖); 项目依赖数量表:为了找到哪个项目可以第一个开始(即没有依赖)。
class Solution {
public int[] sortItems(int n, int m, int[] group, List<List<Integer>> beforeItems) {
// 创建组表:id是组号,value是组里面的项目号
List<List<Integer>> groupList = new ArrayList<>();
// 初始化
for(int i = 0; i < m + n; i++)
groupList.add(new ArrayList<Integer>());
// 记录都有哪些组号
List<Integer> groupIds = new ArrayList<>();
// 初始化
for(int i = 0; i < m + n; i++)
groupIds.add(i);
// 为-1的组分配新组,并给groupList加入数据
int newGroup = m;
for(int i = 0; i < n; i++){
if(group[i] == -1)
group[i] = newGroup++;
groupList.get(group[i]).add(i);
}
// 组的依赖关系:id为组号,value为依赖该组(id)的其他组
// 对于value来说,该组(id组)没完成之前value无法完成
List<List<Integer>> groupGraph = new ArrayList<>();
// 项目依赖,同上
List<List<Integer>> itemGraph = new ArrayList<>();
// 初始化
for(int i = 0; i < m + n; i++)
groupGraph.add(new ArrayList<Integer>());
for(int i = 0; i < n; i++)
itemGraph.add(new ArrayList<Integer>());
// 只有上面的依赖,对于每个组来说,很方便找到他们的后续
// 但是找到自由的组(自己不依赖其他人)却不方便
// 记录组/项目的依赖数就是用来解决这个问题的
int[] groupDegree = new int[m + n];
int[] itemDegree = new int[n];
// 遍历beforeItems,初始化上面四个值
for(int i = 0; i < n; i++){
// 当前项目的组号
int nowGroup = group[i];
// 当前项目所依赖的项目
List<Integer> depended = beforeItems.get(i);
for(int item : depended){
// depended 所属的组
int itemGroup = group[item];
// 如果属于同一个组,则需要更新项目依赖,否则更新组依赖
// 并记录依赖数
if(nowGroup == itemGroup){
itemGraph.get(item).add(i);
itemDegree[i]++;
}else{
groupGraph.get(itemGroup).add(nowGroup);
groupDegree[nowGroup]++;
}
}
}
// 好了,该记录的都记录完了
// 接下来根据组记录更新下组的先后顺序
List<Integer> sortedGroupList = sortByGraph(groupDegree, groupGraph, groupIds);
if(sortedGroupList.size() == 0)
return new int[0];
// 知道组的先后顺序了,那么一个组一个组的更新每个组内的先后顺序就ok了
int answer[] = new int[n];
int index = 0;
for(int sortedGroup : sortedGroupList){
List<Integer> items = groupList.get(sortedGroup);
List<Integer> sortedItems = sortByGraph(itemDegree, itemGraph, items);
if(sortedItems.size() != items.size())
return new int[0];
for(int item : sortedItems)
answer[index++] = item;
}
return answer;
}
private List<Integer> sortByGraph(int[] degree,
List<List<Integer>> graph, List<Integer> items){
// 根据依赖数量、依赖关系 来更新 items 列表
Queue<Integer> queue = new LinkedList<>();
List<Integer> answer = new ArrayList<>();
for(int item : items){
if(degree[item] == 0)
queue.offer(item);
}
while(!queue.isEmpty()){
int tmp = queue.poll();
answer.add(tmp);
List<Integer> depend = graph.get(tmp);
for(int item : depend){
if(--degree[item] == 0)
queue.offer(item);
}
}
if(answer.size() != items.size())
return new ArrayList<Integer>();
return answer;
}
}
public 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;
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 (int beforeItem : beforeItems.get(i)) {
int beforeGroup = group[beforeItem];
if (beforeGroup != currentGroup) {
groupAdj[beforeGroup].add(currentGroup);
groupsIndegree[currentGroup]++;
}
}
}
for (int i = 0; i < n; i++) {
for (Integer item : beforeItems.get(i)) {
itemAdj[item].add(i);
itemsIndegree[i]++;
}
}
List<Integer> groupsList = topologicalSort(groupAdj, groupsIndegree, m);
if (groupsList.size() == 0) {
return new int[0];
}
List<Integer> itemsList = topologicalSort(itemAdj, itemsIndegree, n);
if (itemsList.size() == 0) {
return new int[0];
}
Map<Integer, List<Integer>> groups2Items = new HashMap<>();
for (Integer item : itemsList) {
groups2Items.computeIfAbsent(group[item], key -> new ArrayList<>()).add(item);
}
List<Integer> res = new ArrayList<>();
for (Integer groupId : groupsList) {
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 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 (int successor : adj[front]) {
inDegree[successor]--;
if (inDegree[successor] == 0) {
queue.offer(successor);
}
}
}
if (res.size() == n) {
return res;
}
return new ArrayList<>();
}
}
时间复杂度:O(n) 空间复杂度:O(n)
const topSort = (deg, graph, items) => {
const Q = [];
for (const item of items) {
if (deg[item] === 0) {
Q.push(item);
}
}
const res = [];
while (Q.length) {
const u = Q.shift();
res.push(u);
for (let i = 0; i < graph[u].length; ++i) {
const v = graph[u][i];
if (--deg[v] === 0) {
Q.push(v);
}
}
}
return res.length == items.length ? res : [];
}
var sortItems = function(n, m, group, beforeItems) {
const groupItem = new Array(n + m).fill(0).map(() => []);
// 组间和组内依赖图
const groupGraph = new Array(n + m).fill(0).map(() => []);
const itemGraph = new Array(n).fill(0).map(() => []);
// 组间和组内入度数组
const groupDegree = new Array(n + m).fill(0);
const itemDegree = new Array(n).fill(0);
const id = new Array(n + m).fill(0).map((v, index) => index);
let leftId = m;
// 给未分配的 item 分配一个 groupId
for (let i = 0; i < n; ++i) {
if (group[i] === -1) {
group[i] = leftId;
leftId += 1;
}
groupItem[group[i]].push(i);
}
// 依赖关系建图
for (let i = 0; i < n; ++i) {
const curGroupId = group[i];
for (const item of beforeItems[i]) {
const beforeGroupId = group[item];
if (beforeGroupId === curGroupId) {
itemDegree[i] += 1;
itemGraph[item].push(i);
} else {
groupDegree[curGroupId] += 1;
groupGraph[beforeGroupId].push(curGroupId);
}
}
}
// 组间拓扑关系排序
const groupTopSort = topSort(groupDegree, groupGraph, id);
if (groupTopSort.length == 0) {
return [];
}
const ans = [];
// 组内拓扑关系排序
for (const curGroupId of groupTopSort) {
const size = groupItem[curGroupId].length;
if (size == 0) {
continue;
}
const res = topSort(itemDegree, itemGraph, groupItem[curGroupId]);
if (res.length === 0) {
return [];
}
for (const item of res) {
ans.push(item);
}
}
return ans;
};
思路
对图不熟悉,直接看题解 代码
class Solution {
public:
using UMIV = unordered_map<int,vector<int>>; //顶点邻接边
using UMII = unordered_map<int, int>;
using VVI = vector<vector<int>>;
using VI = vector<int>;
UMIV sub; //保存小组内可执行任务序列
vector<int> sortItems(int n, int m, vector<int>& group,
vector<vector<int>>& beforeItems) {
//如果任务不属于任何小组,说明该任务可以独属于一组,给该任务新建虚拟组
//直接加入到sub中,不走后续组内拓扑排序
for (int i = 0; i < n;i++)
{
if (group[i]==-1)
{
group[i] = m++;
}
}
//保存一个小组内任务
vector<vector<int>> gg(m);
for (int i = 0; i < n;++i)
{
gg[group[i]].push_back(i);
}
//按照项目拓扑排序
for (int i = 0; i < gg.size();++i)
{
if (gg[i].size()==1)
{
int itemId = gg[i][0];
sub[group[itemId]] = { itemId };
continue;
}
bool f = topoSort(i, gg[i], beforeItems);
if (f==false)
{
return{};
}
}
//按照小组排序
VI groups;
for (int i = 0; i < m;++i)
{
groups.push_back(i);
}
VVI newbefore(m);
for (int i = 0; i < n;i++)
{
for (int j = 0; j < beforeItems[i].size();j++)
{
if (group[i]!=beforeItems[i][j])
{
newbefore[i].push_back(beforeItems[i][j]);
}
}
}
if (!topoSort(m,groups,newbefore))
{
return{};
}
VI rs;
for (auto v:sub[m])
{
rs.insert(rs.end(), sub[v].begin(), sub[v].end());
}
return rs;
}
bool topoSort(int gpid,VI& group,VVI& before)
{
int n = group.size();//顶点个数
UMII degree;//每个顶点入度
UMIV g; //图
for (int i = 0; i < n;i++)
{
degree[group[i]] = 0;
g[group[i]] = vector<int>();
}
for (int i = 0; i < n;i++)
{
int idx = group[i];
for (int j = 0; j < before[idx].size(); ++j)
{
int last = before[idx][j];
if (degree.find(last)==degree.end())
{
continue;
}
g[last].push_back(idx);
degree[idx]++;
}
}
VI res;
queue<int> q;
for (int i = 0; i < n;i++)
{
if (degree[group[i]] == 0)
{
q.push(group[i]);
}
}
while (!q.empty())
{
int cur = q.front();
q.pop();
res.push_back(cur);
if (g[cur].size()!=0)
{
for (int i = 0; i < g[cur].size();++i)
{
if (--degree[g[cur][i]]==0)
{
q.push(g[cur][i]);
}
}
}
}
sub[gpid] = move(res);
return sub[gpid].size() == n;
}
};
const sortItems = function (n, m, group, beforeItems) { const vertexs = new Map(); const groupVertexs = new Map(); let groupNo = m; for (let i = 0; i < n; i++) { vertexs.set(i, { neighbors: new Set(), indegree: 0, }); if (group[i] === -1) { group[i] = groupNo++; } if (!groupVertexs.has(group[i])) { groupVertexs.set(group[i], { v: new Set(), neighbors: new Set(), indegree: 0, }); } groupVertexs.get(group[i]).v.add(i); }
for (let i = 0; i < n; i++) { for (const before of beforeItems[i]) { if (!vertexs.get(before).neighbors.has(i)) { vertexs.get(i).indegree += 1; } vertexs.get(before).neighbors.add(i);
const groupOfBefore = group[before];
if (groupOfBefore === group[i]) continue;
if (!groupVertexs.get(groupOfBefore).neighbors.has(group[i])) {
groupVertexs.get(group[i]).indegree += 1;
}
groupVertexs.get(groupOfBefore).neighbors.add(group[i]);
}
}
const zeroGroup = []; for (const group of groupVertexs) { if (group[1].indegree === 0) { zeroGroup.push(group[0]); } } const result = []; let cntGroup = 0; let cntV = 0; const groupTotal = groupVertexs.size;
while (zeroGroup.length) { const top = zeroGroup.pop(); cntGroup += 1; const v = groupVertexs.get(top).v; const total = v.size; const zero = [];
for (const i of v) {
if (vertexs.get(i).indegree === 0) {
zero.push(i);
}
}
while (zero.length) {
const it = zero.pop();
result.push(it);
for (const n of vertexs.get(it).neighbors) {
vertexs.get(n).indegree -= 1;
if (v.has(n) && vertexs.get(n).indegree === 0) {
zero.push(n);
}
}
}
if (result.length - cntV !== total) {
return [];
}
cntV = result.length;
for (const groupneigbor of groupVertexs.get(top).neighbors) {
groupVertexs.get(groupneigbor).indegree -= 1;
if (groupVertexs.get(groupneigbor).indegree === 0) {
zeroGroup.push(groupneigbor);
}
}
} return cntGroup === groupTotal ? result : []; };
又是直接看题解的一天
class Solution:
def tp_sort(self, items, indegree, neighbors):
q = collections.deque([])
ans = []
for item in items:
if not indegree[item]:
q.append(item)
while q:
cur = q.popleft()
ans.append(cur)
for neighbor in neighbors[cur]:
indegree[neighbor] -= 1
if not indegree[neighbor]:
q.append(neighbor)
return ans
def sortItems(self, n: int, m: int, group: List[int], pres: List[List[int]]) -> List[int]:
max_group_id = m
for project in range(n):
if group[project] == -1:
group[project] = max_group_id
max_group_id += 1
project_indegree = collections.defaultdict(int)
group_indegree = collections.defaultdict(int)
project_neighbors = collections.defaultdict(list)
group_neighbors = collections.defaultdict(list)
group_projects = collections.defaultdict(list)
for project in range(n):
group_projects[group[project]].append(project)
for pre in pres[project]:
if group[pre] != group[project]:
# 小组关系图
group_indegree[group[project]] += 1
group_neighbors[group[pre]].append(group[project])
else:
# 项目关系图
project_indegree[project] += 1
project_neighbors[pre].append(project)
ans = []
group_queue = self.tp_sort([i for i in range(max_group_id)], group_indegree, group_neighbors)
if len(group_queue) != max_group_id:
return []
for group_id in group_queue:
project_queue = self.tp_sort(group_projects[group_id], project_indegree, project_neighbors)
if len(project_queue) != len(group_projects[group_id]):
return []
ans += project_queue
return ans
public 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;
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 (int beforeItem : beforeItems.get(i)) {
int beforeGroup = group[beforeItem];
if (beforeGroup != currentGroup) {
groupAdj[beforeGroup].add(currentGroup);
groupsIndegree[currentGroup]++;
}
}
}
for (int i = 0; i < n; i++) {
for (Integer item : beforeItems.get(i)) {
itemAdj[item].add(i);
itemsIndegree[i]++;
}
}
List<Integer> groupsList = topologicalSort(groupAdj, groupsIndegree, m);
if (groupsList.size() == 0) {
return new int[0];
}
List<Integer> itemsList = topologicalSort(itemAdj, itemsIndegree, n);
if (itemsList.size() == 0) {
return new int[0];
}
Map<Integer, List<Integer>> groups2Items = new HashMap<>();
for (Integer item : itemsList) {
groups2Items.computeIfAbsent(group[item], key -> new ArrayList<>()).add(item);
}
List<Integer> res = new ArrayList<>();
for (Integer groupId : groupsList) {
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 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 (int successor : adj[front]) {
inDegree[successor]--;
if (inDegree[successor] == 0) {
queue.offer(successor);
}
}
}
if (res.size() == n) {
return res;
}
return new ArrayList<>();
}
}
学习官方题解。首先,要掌握拓扑排序,拓扑排序适用于一个任务中有多个子任务,子任务可能有优先级(但不能互相交叉,能够满足有向无环图)的情况。这题项目管理,说明有的项目要在一些项目之前,其实就很好的满足拓扑排序的定义,但这题,除了项目有顺序,组也有顺序,这个就需要建立双层的图关系,也就是项目图关系和组图关系。项目图关系是题目给出的,那么组图关系是什么呢?其实就是当组里面项目有优先关系的时候,组的优先关系就定了。最后就是没有分组的怎么办呢?没有分组的直接自增地给一个组即可。官方思路非常清晰,但是这题知识点比较多,不是太好想
from collections import deque, defaultdict
class Solution:
def tp_sort(self, items, indegree, neighbors) -> List[int]:
res = []
q = deque()
for item in items:
if not indegree[item]:
q.append(item)
while q:
cur = q.popleft()
res.append(cur)
for neighbor in neighbors[cur]:
indegree[neighbor] -= 1
if not indegree[neighbor]:
q.append(neighbor)
return res
def sortItems(self, n: int, m: int, group: List[int], beforeItems: List[List[int]]) -> List[int]:
max_group_id = m
# 无组的项目,从m开始自增地+1分配给一个组
for project in range(n):
if group[project] == -1:
group[project] = max_group_id
max_group_id += 1
# 项目关系
project_indegree = defaultdict(int)
project_neighbors = defaultdict(list)
# 小组关系
group_indegree = defaultdict(int)
group_neighbors = defaultdict(list)
# 组和项目的对应关系
group_projects = defaultdict(list)
for project in range(n):
group_projects[group[project]].append(project)
# 每个项目都可能有before
for pre in beforeItems[project]:
# 如果pre和project不在一个组,说明pre的组要在project组前面,处理组关系
# 小组关系图
if group[pre] != group[project]:
group_indegree[group[project]] += 1
group_neighbors[group[pre]].append(group[project])
# 项目关系图
else:
project_indegree[project] += 1
project_neighbors[pre].append(project)
res = []
# 对组拓扑排序,因为无组的都分配了一个组,所以现在有max_group_id个组
group_queue = self.tp_sort([i for i in range(max_group_id)], group_indegree, group_neighbors)
# 如果排序完长度和原来不一致,说明无法正确拓扑排序
if len(group_queue) != max_group_id:
return []
for group_id in group_queue:
project_queue = self.tp_sort(group_projects[group_id], project_indegree, project_neighbors)
if len(project_queue) != len(group_projects[group_id]):
return []
res += project_queue
return res
public int[] sortItems(int n, int m, int[] group, List<List<Integer>> beforeItems) {
List<List<Integer>> groupItem = new ArrayList<>();//项目分组
for(int i = 0;i < n + m;i++){//初始化小组
groupItem.add(new ArrayList<>());
}
int gId = m;//新的组号从m开始
for(int i = 0;i < group.length;i++){
if(group[i] == -1)group[i] = gId++;//没有id的加上组id
groupItem.get(group[i]).add(i);//同一组的放在一起
}
List<List<Integer>> graphInGroup = new ArrayList<>();//组内拓扑关系
List<List<Integer>> graphOutGroup = new ArrayList<>();//组间拓扑关系
for(int i = 0;i < n + m;i++){//初始化拓扑关系
graphOutGroup.add(new ArrayList<>());
if(i >= n)continue;
graphInGroup.add(new ArrayList<>());
}
List<Integer> groupId = new ArrayList<>();//所有组id
for(int i = 0;i < n + m;i++){
groupId.add(i);
}
// 需要拓扑排序 所以结点的入度必不可少 两个数组分别维护不同结点的入度
int[] degInGroup = new int[n];//组内 结点入度 (组内项目入度)
int[] degOutGroup = new int[n + m];//组间 结点入度(小组入度)
for(int i = 0;i < beforeItems.size();i++){//遍历关系
int curGroupId = group[i];//当前项目i所属的小组id
List<Integer> beforeItem = beforeItems.get(i);
for(Integer item : beforeItem){
if(group[item] == curGroupId){//同一组 修改组内拓扑
degInGroup[i]++;// 组内结点的入度+1
graphInGroup.get(item).add(i);//item 在 i之前
}else{
degOutGroup[curGroupId]++;// 小组间的结点入度 + 1
graphOutGroup.get(group[item]).add(curGroupId);// group[item] 小组 在 curGroupId 之前
}
}
}
//组间拓扑排序,也就是小组之间的拓扑排序,需要的参数 小组结点的入度degOutGroup,所有的小组groupId,组间的拓扑关系图graphOutGroup
List<Integer> outGroupTopSort = topSort(degOutGroup,groupId,graphOutGroup);
if(outGroupTopSort.size() == 0)return new int[0];//无法拓扑排序 返回
int[] res = new int[n];
int index = 0;
for(Integer gid : outGroupTopSort){//遍历排序后的小组id
List<Integer> items = groupItem.get(gid);//根据小组id 拿到这一小组中的所有成员
if(items.size() == 0)continue;
//组内拓扑排序,需要的参数 组内结点的入度degInGroup,组内的所有的结点groupItem.get(gid),组内的拓扑关系图graphInGroup
List<Integer> inGourpTopSort = topSort(degInGroup,groupItem.get(gid),graphInGroup);
if(inGourpTopSort.size() == 0)return new int[0];//无法拓扑排序 返回
for(int item : inGourpTopSort){//排序后,依次的放入答案集合当中
res[index++] = item;
}
}
return res;
}
public List<Integer> topSort(int[] deg, List<Integer> items,List<List<Integer>> graph){
Queue<Integer> queue = new LinkedList<>();
for(Integer item:items){
if(deg[item] == 0)queue.offer(item);
}
List<Integer> res = new ArrayList<>();
while(!queue.isEmpty()){
int cur = queue.poll();
res.add(cur);
for(int neighbor: graph.get(cur)){
if(--deg[neighbor] == 0){
queue.offer(neighbor);
}
}
}
return res.size() == items.size() ? res : new ArrayList<>();
}
C++ Code:
class Solution {
public:
vector<int> topSort(vector<int>& deg, vector<vector<int>>& graph, vector<int>& items) {
queue<int> Q;
for (auto& item: items) {
if (deg[item] == 0) {
Q.push(item);
}
}
vector<int> res;
while (!Q.empty()) {
int u = Q.front();
Q.pop();
res.emplace_back(u);
for (auto& v: graph[u]) {
if (--deg[v] == 0) {
Q.push(v);
}
}
}
return res.size() == items.size() ? res : vector<int>{};
}
vector<int> sortItems(int n, int m, vector<int>& group, vector<vector<int>>& beforeItems) {
vector<vector<int>> groupItem(n + m);
vector<vector<int>> groupGraph(n + m);
vector<vector<int>> itemGraph(n);
vector<int> groupDegree(n + m, 0);
vector<int> itemDegree(n, 0);
vector<int> id;
for (int i = 0; i < n + m; ++i) {
id.emplace_back(i);
}
int leftId = m;
for (int i = 0; i < n; ++i) {
if (group[i] == -1) {
group[i] = leftId;
leftId += 1;
}
groupItem[group[i]].emplace_back(i);
}
for (int i = 0; i < n; ++i) {
int curGroupId = group[i];
for (auto& item: beforeItems[i]) {
int beforeGroupId = group[item];
if (beforeGroupId == curGroupId) {
itemDegree[i] += 1;
itemGraph[item].emplace_back(i);
} else {
groupDegree[curGroupId] += 1;
groupGraph[beforeGroupId].emplace_back(curGroupId);
}
}
}
vector<int> groupTopSort = topSort(groupDegree, groupGraph, id);
if (groupTopSort.size() == 0) {
return vector<int>{};
}
vector<int> ans;
for (auto& curGroupId: groupTopSort) {
int size = groupItem[curGroupId].size();
if (size == 0) {
continue;
}
vector<int> res = topSort(itemDegree, itemGraph, groupItem[curGroupId]);
if (res.size() == 0) {
return vector<int>{};
}
for (auto& item: res) {
ans.emplace_back(item);
}
}
return ans;
}
};
抄作业
class Solution:
def sortItems(self, n: int, m: int, group: List[int], beforeItems: List[List[int]]) -> List[int]:
dep = [0] * n # 项目依赖数,为0时,该项目才能执行
group_dep = [0] * m # 小组依赖数(小组管理的所有项目的依赖总数),为0时,该小组才能开始执行项目
other_queue = [] # 暂无分组的子队列
group_queue = [[] for _ in range(m)] # 各组的子队列
queue_queue = [] # 组队列,控制组与组之间的执行顺序,因为每个组的项目要一起执行
dependedBy = [[] for _ in range(n)] # 项目间的具体依赖
# 初始化依赖数、小组依赖数、项目间的具体依赖
for i, l in enumerate(beforeItems):
dep[i] = len(l)
gi = group[i] # 项目i对应的组号
# 项目i没有依赖的项目,直接入队,准备执行
if not l:
(group_queue[gi] if gi != -1 else other_queue).append(i)
# 遍历项目i的依赖项目
for j in l:
# j是i的依赖
dependedBy[j].append(i)
# 项目i有已知分组,且没有形成了环,小组依赖数增加1
if gi != -1 and group[j] != gi:
group_dep[gi] += 1
# 初始化组队列,组队列的每个元素就是对应小组的子队列
for i, gd in enumerate(group_dep):
if not gd:
queue_queue.append(group_queue[i])
result = [] # 存储结果的列表
while True:
# 取出当前执行任务的小组,优先是有分组的
if queue_queue:
current_queue = queue_queue.pop()
elif other_queue:
current_queue = other_queue
else:
# 不能形成有效的序列,直接返回[]
if len(result) < n:
return []
# 可以形成有效的序列,返回result
else:
return result
# 遍历当前组的子队列
while current_queue:
p = current_queue.pop() # 项目p
result.append(p) # 项目p执行
gp = group[p] # 执行项目p的组号
# 遍历所有依赖p的项目(即p执行了,这些才能执行)
for i in dependedBy[p]:
gi = group[i] # 项目i的组号
dep[i] -= 1 # 依赖数减一
# 没有依赖了,可以入队准备执行
if not dep[i]:
(group_queue[gi] if gi != -1 else other_queue).append(i)
# 项目i有已知分组,且没有形成了环
if gi != -1 and gi != gp:
group_dep[gi] -= 1 # 组依赖数减一
# 没有依赖了,该组可以开始执行
if not group_dep[gi]:
queue_queue.append(group_queue[gi])
NONE
class Solution {
public int[] sortItems(int n, int m, int[] group, List<List<Integer>> beforeItems) {
List<List<Integer>> groupItem = new ArrayList<List<Integer>>();
for (int i = 0; i < n + m; ++i) {
groupItem.add(new ArrayList<Integer>());
}
// 组间和组内依赖图
List<List<Integer>> groupGraph = new ArrayList<List<Integer>>();
for (int i = 0; i < n + m; ++i) {
groupGraph.add(new ArrayList<Integer>());
}
List<List<Integer>> itemGraph = new ArrayList<List<Integer>>();
for (int i = 0; i < n; ++i) {
itemGraph.add(new ArrayList<Integer>());
}
// 组间和组内入度数组
int[] groupDegree = new int[n + m];
int[] itemDegree = new int[n];
List<Integer> id = new ArrayList<Integer>();
for (int i = 0; i < n + m; ++i) {
id.add(i);
}
int leftId = m;
// 给未分配的 item 分配一个 groupId
for (int i = 0; i < n; ++i) {
if (group[i] == -1) {
group[i] = leftId;
leftId += 1;
}
groupItem.get(group[i]).add(i);
}
// 依赖关系建图
for (int i = 0; i < n; ++i) {
int curGroupId = group[i];
for (int item : beforeItems.get(i)) {
int beforeGroupId = group[item];
if (beforeGroupId == curGroupId) {
itemDegree[i] += 1;
itemGraph.get(item).add(i);
} else {
groupDegree[curGroupId] += 1;
groupGraph.get(beforeGroupId).add(curGroupId);
}
}
}
// 组间拓扑关系排序
List<Integer> groupTopSort = topSort(groupDegree, groupGraph, id);
if (groupTopSort.size() == 0) {
return new int[0];
}
int[] ans = new int[n];
int index = 0;
// 组内拓扑关系排序
for (int curGroupId : groupTopSort) {
int size = groupItem.get(curGroupId).size();
if (size == 0) {
continue;
}
List<Integer> res = topSort(itemDegree, itemGraph, groupItem.get(curGroupId));
if (res.size() == 0) {
return new int[0];
}
for (int item : res) {
ans[index++] = item;
}
}
return ans;
}
public List<Integer> topSort(int[] deg, List<List<Integer>> graph, List<Integer> items) {
Queue<Integer> queue = new LinkedList<Integer>();
for (int item : items) {
if (deg[item] == 0) {
queue.offer(item);
}
}
List<Integer> res = new ArrayList<Integer>();
while (!queue.isEmpty()) {
int u = queue.poll();
res.add(u);
for (int v : graph.get(u)) {
if (--deg[v] == 0) {
queue.offer(v);
}
}
}
return res.size() == items.size() ? res : new ArrayList<Integer>();
}
}
O(V+E) O(V+E)
var sortItems = function(n, m, group, beforeItems) {
let ans = [];
const groupGraph = new Map, itemGraph = new Map(), groupItemMap = new Map();
let maxGroupNum = m;
for(let i = 0; i < n; i++) {
if(group[i] === -1) {
group[i] = maxGroupNum; maxGroupNum++;
}
}
// groupItemMap
for(let i = 0; i < n; i++) {
if(!groupItemMap.has(group[i])) groupItemMap.set(group[i], []);
groupItemMap.get(group[i]).push(i);
}
for(let i = 0; i < beforeItems.length; i++) {
let afterItemId = i, beforeItemIds = beforeItems[i];
for(let beforeItemId of beforeItemIds) {
let beforeGroupId = group[beforeItemId], afterGroupId = group[afterItemId];
if(beforeGroupId !== afterGroupId) {
if(!groupGraph.has(beforeGroupId)) groupGraph.set(beforeGroupId, []);
groupGraph.get(beforeGroupId).push(afterGroupId);
} else {
if(!itemGraph.has(beforeGroupId)) itemGraph.set(beforeGroupId, new Map());
if(!itemGraph.get(beforeGroupId).has(beforeItemId)) itemGraph.get(beforeGroupId).set(beforeItemId, []);
itemGraph.get(beforeGroupId).get(beforeItemId).push(afterItemId);
}
}
}
let groupDegrees = Array(maxGroupNum).fill(0);
groupGraph.forEach((values) => values.forEach((value) => groupDegrees[value]++));
let sortedGroupList = topoSort(groupDegrees, groupGraph, maxGroupNum);
let items, itemDegrees, sortedItemList;
for(let groupId of sortedGroupList) {
if(!groupItemMap.has(groupId)) continue;
items = groupItemMap.get(groupId);
if(!itemGraph.has(groupId)) {
ans = ans.concat(items);
} else {
itemDegrees = Array(n).fill(-1);
items.forEach((item) => itemDegrees[item] = 0); // 存在的item置为0
itemGraph.get(groupId).forEach((values) => values.forEach((value) => itemDegrees[value]++));
sortedItemList = topoSort(itemDegrees, itemGraph.get(groupId), items.length);
if(sortedItemList.length === 0) return [];
ans = ans.concat(sortedItemList);
}
}
return ans;
};
var topoSort = function(degrees, graph, len) {
const ans = [], q = [];
for(let i = 0; i < degrees.length; i++) {
if(degrees[i] === 0) q.push(i);
}
while(q.length !== 0) {
let item = q.shift(); ans.push(item);
if(graph.has(item)) {
for(let child of graph.get(item)) {
degrees[child]--;
if(degrees[child] === 0) q.push(child);
}
}
}
return ans.length === len ? ans : [];
}
class Solution:
def tp_sort(self, items, indegree, neighbors):
q = collections.deque([])
ans = []
for item in items:
if not indegree[item]:
q.append(item)
while q:
cur = q.popleft()
ans.append(cur)
for neighbor in neighbors[cur]:
indegree[neighbor] -= 1
if not indegree[neighbor]:
q.append(neighbor)
return ans
def sortItems(self, n: int, m: int, group: List[int], pres: List[List[int]]) -> List[int]:
max_group_id = m
for project in range(n):
if group[project] == -1:
group[project] = max_group_id
max_group_id += 1
project_indegree = collections.defaultdict(int)
group_indegree = collections.defaultdict(int)
project_neighbors = collections.defaultdict(list)
group_neighbors = collections.defaultdict(list)
group_projects = collections.defaultdict(list)
for project in range(n):
group_projects[group[project]].append(project)
for pre in pres[project]:
if group[pre] != group[project]:
# 小组关系图
group_indegree[group[project]] += 1
group_neighbors[group[pre]].append(group[project])
else:
# 项目关系图
project_indegree[project] += 1
project_neighbors[pre].append(project)
ans = []
group_queue = self.tp_sort([i for i in range(max_group_id)], group_indegree, group_neighbors)
if len(group_queue) != max_group_id:
return []
for group_id in group_queue:
project_queue = self.tp_sort(group_projects[group_id], project_indegree, project_neighbors)
if len(project_queue) != len(group_projects[group_id]):
return []
ans += project_queue
return ans
/**
* @param {number} n
* @param {number} m
* @param {number[]} group
* @param {number[][]} beforeItems
* @return {number[]}
*/
var sortItems = function (n, m, group, beforeItems) {
const grahG = [],
degG = new Uint16Array(n + m),
idsG = [],
grahI = [],
degI = new Uint16Array(n),
idsI = [],
r = []
for (let i = 0; i < n; i++) {
if (group[i] === -1) {
idsG[m] = m // 从组数起分配,避免重复
group[i] = m++
} else idsG[group[i]] = group[i]
if (!idsI[group[i]]) idsI[group[i]] = [] // 同组项目,放入到一起
idsI[group[i]].push(i)
}
for (let i = 0; i < n; i++) {
for (let j = 0; j < beforeItems[i].length; j++) {
const itemI = beforeItems[i][j]
if (group[i] === group[itemI]) {
// 同组,收集 项目 依赖
degI[i]++
if (!grahI[itemI]) grahI[itemI] = []
grahI[itemI].push(i)
} else {
// 不同组,收集 组 依赖
degG[group[i]]++
if (!grahG[group[itemI]]) grahG[group[itemI]] = []
grahG[group[itemI]].push(group[i])
}
}
}
const idsGS = sort(
idsG.filter((v) => v !== void 0),
grahG,
degG
) // 组排序
if (idsGS.length === 0) return []
for (let i = 0; i < idsGS.length; i++) {
// 组有序,组内项目排序
if (!idsI[idsGS[i]]) continue
const idsIS = sort(idsI[idsGS[i]], grahI, degI)
if (idsIS.length === 0) return []
r.push(...idsIS)
}
return r
}
const sort = (ids, grah, deg) => {
// 拓扑排序:id列表,图,入度
const q = [],
r = []
let start = 0
for (let i = 0; i < ids.length; i++) if (deg[ids[i]] === 0) q.push(ids[i])
while (start < q.length) {
const n = q[start++]
r.push(n)
if (!grah[n]) continue
for (let i = 0; i < grah[n].length; i++)
if (--deg[grah[n][i]] === 0) q.push(grah[n][i])
}
return r.length === ids.length ? r : []
}
class Solution {
public:
vector<int> topSort(vector<int>& deg, vector<vector<int>>& graph, vector<int>& items) {
queue<int> Q;
for (auto& item: items) {
if (deg[item] == 0) {
Q.push(item);
}
}
vector<int> res;
while (!Q.empty()) {
int u = Q.front();
Q.pop();
res.emplace_back(u);
for (auto& v: graph[u]) {
if (--deg[v] == 0) {
Q.push(v);
}
}
}
return res.size() == items.size() ? res : vector<int>{};
}
vector<int> sortItems(int n, int m, vector<int>& group, vector<vector<int>>& beforeItems) {
vector<vector<int>> groupItem(n + m);
vector<vector<int>> groupGraph(n + m);
vector<vector<int>> itemGraph(n);
vector<int> groupDegree(n + m, 0);
vector<int> itemDegree(n, 0);
vector<int> id;
for (int i = 0; i < n + m; ++i) {
id.emplace_back(i);
}
int leftId = m;
for (int i = 0; i < n; ++i) {
if (group[i] == -1) {
group[i] = leftId;
leftId += 1;
}
groupItem[group[i]].emplace_back(i);
}
for (int i = 0; i < n; ++i) {
int curGroupId = group[i];
for (auto& item: beforeItems[i]) {
int beforeGroupId = group[item];
if (beforeGroupId == curGroupId) {
itemDegree[i] += 1;
itemGraph[item].emplace_back(i);
} else {
groupDegree[curGroupId] += 1;
groupGraph[beforeGroupId].emplace_back(curGroupId);
}
}
}
vector<int> groupTopSort = topSort(groupDegree, groupGraph, id);
if (groupTopSort.size() == 0) {
return vector<int>{};
}
vector<int> ans;
for (auto& curGroupId: groupTopSort) {
int size = groupItem[curGroupId].size();
if (size == 0) {
continue;
}
vector<int> res = topSort(itemDegree, itemGraph, groupItem[curGroupId]);
if (res.size() == 0) {
return vector<int>{};
}
for (auto& item: res) {
ans.emplace_back(item);
}
}
return ans;
}
};
两次拓扑排序,第一次先排各个组内的项目,第二次排组,具体看注释
class Solution {
public:
unordered_map<int, vector<int>> map; // group -> projects
// projs指的是在第groupId个组当中,他有的项目。projs[0][1][2]即为第1,2,3个项目
bool topoSort(int groupId, vector<int>& projs, vector<vector<int>>& beforeItems) {
int n = projs.size();
unordered_map<int, int> indegree; // degree
unordered_map<int, vector<int>> neighbors; // graph
// initialization
for (int i = 0; i < n; ++i) {
indegree[projs[i]] = 0;
neighbors[projs[i]] = vector<int>();
}
for (int i = 0; i < n; ++i) {
int idx = projs[i];
if (beforeItems[idx].size() == 0) continue;
for (int j = 0; j < beforeItems[idx].size(); ++j) {
//
if (indegree.find(beforeItems[idx][j]) == indegree.end()) continue;
indegree[idx]++;
// proj needed be done first -> others
neighbors[beforeItems[idx][j]].push_back(idx);
}
}
vector<int> ans;
queue<int> q;
// 入度为0的(不需要前置的)先加入队列
for (int i = 0; i < n; ++i) {
if (indegree[projs[i]] == 0) {
q.push(projs[i]);
}
}
while (!q.empty()) {
int curr = q.front();
q.pop();
ans.push_back(curr);
if (neighbors[curr].size() != 0) {
for (auto& neighbor: neighbors[curr]) {
if (--indegree[neighbor] == 0) {
q.push(neighbor);
}
}
}
}
map[groupId] = move(ans);
return map[groupId].size() == n;
}
vector<int> sortItems(int n, int m, vector<int>& group, vector<vector<int>>& beforeItems) {
// 给没有分组的小组加入一个新的组
for (int i = 0; i < n; i++) {
if (group[i] == -1) {
group[i] = m++;
}
}
// 在拓扑排序之前保存各个小组有的项目
vector<vector<int>> projInGroup(m); // groupId -> projectIds
for (int i = 0; i < n; ++i) {
projInGroup[group[i]].push_back(i);
}
// 根据项目拓扑排序
for (int i = 0; i < projInGroup.size(); ++i) {
// 如果只有一个项目,不需要拓扑
if (projInGroup[i].size() == 1) {
int projId = projInGroup[i][0]; // group i中的唯一一个project id
map[group[projId]].push_back(projId);
continue;
}
bool hasResult = topoSort(i, projInGroup[i], beforeItems);
if (!hasResult) return {};
}
// 根据小组排序
vector<int> team;
// 总共原有的组(不包括未被分组的),用来做排序
for (int i = 0; i < m; ++i) team.push_back(i);
vector<vector<int>> newBefore(m);
for (int i = 0; i < n; ++i) {
for (int j = 0; j < beforeItems[i].size(); ++j) {
int prev = group[beforeItems[i][j]];
// 当前项目的小组的前置项目小组和当前小组如果不一致(跨小组前置要求)
if (prev != group[i]) {
// 把这个其他组的项目的组号加入到vector当中
// 例如组3有一个项目需要先完成组0;idx[3] -> {0},是一个beforeGroup的概念
newBefore[group[i]].push_back(prev);
}
}
}
if (!topoSort(m, team, newBefore)) return {};
vector<int> ans;
for (auto v: map[m]) {
ans.insert(ans.end(), map[v].begin(), map[v].end());
}
return ans;
}
};
参考官方题解
class Solution {
public int[] sortItems(int n, int m, int[] group, List<List<Integer>> beforeItems) {
List<List<Integer>> groupItem = new ArrayList<List<Integer>>();
for (int i = 0; i < n + m; ++i) {
groupItem.add(new ArrayList<Integer>());
}
// 组间和组内依赖图
List<List<Integer>> groupGraph = new ArrayList<List<Integer>>();
for (int i = 0; i < n + m; ++i) {
groupGraph.add(new ArrayList<Integer>());
}
List<List<Integer>> itemGraph = new ArrayList<List<Integer>>();
for (int i = 0; i < n; ++i) {
itemGraph.add(new ArrayList<Integer>());
}
// 组间和组内入度数组
int[] groupDegree = new int[n + m];
int[] itemDegree = new int[n];
List<Integer> id = new ArrayList<Integer>();
for (int i = 0; i < n + m; ++i) {
id.add(i);
}
int leftId = m;
// 给未分配的 item 分配一个 groupId
for (int i = 0; i < n; ++i) {
if (group[i] == -1) {
group[i] = leftId;
leftId += 1;
}
groupItem.get(group[i]).add(i);
}
// 依赖关系建图
for (int i = 0; i < n; ++i) {
int curGroupId = group[i];
for (int item : beforeItems.get(i)) {
int beforeGroupId = group[item];
if (beforeGroupId == curGroupId) {
itemDegree[i] += 1;
itemGraph.get(item).add(i);
} else {
groupDegree[curGroupId] += 1;
groupGraph.get(beforeGroupId).add(curGroupId);
}
}
}
// 组间拓扑关系排序
List<Integer> groupTopSort = topSort(groupDegree, groupGraph, id);
if (groupTopSort.size() == 0) {
return new int[0];
}
int[] ans = new int[n];
int index = 0;
// 组内拓扑关系排序
for (int curGroupId : groupTopSort) {
int size = groupItem.get(curGroupId).size();
if (size == 0) {
continue;
}
List<Integer> res = topSort(itemDegree, itemGraph, groupItem.get(curGroupId));
if (res.size() == 0) {
return new int[0];
}
for (int item : res) {
ans[index++] = item;
}
}
return ans;
}
public List<Integer> topSort(int[] deg, List<List<Integer>> graph, List<Integer> items) {
Queue<Integer> queue = new LinkedList<Integer>();
for (int item : items) {
if (deg[item] == 0) {
queue.offer(item);
}
}
List<Integer> res = new ArrayList<Integer>();
while (!queue.isEmpty()) {
int u = queue.poll();
res.add(u);
for (int v : graph.get(u)) {
if (--deg[v] == 0) {
queue.offer(v);
}
}
}
return res.size() == items.size() ? res : new ArrayList<Integer>();
}
}
class Solution:
def tp_sort(self, items, indegree, neighbors):
q = collections.deque([])
ans = []
for item in items:
if not indegree[item]:
q.append(item)
while q:
cur = q.popleft()
ans.append(cur)
for neighbor in neighbors[cur]:
indegree[neighbor] -= 1
if not indegree[neighbor]:
q.append(neighbor)
return ans
def sortItems(self, n: int, m: int, group: List[int], pres: List[List[int]]) -> List[int]:
max_group_id = m
for project in range(n):
if group[project] == -1:
group[project] = max_group_id
max_group_id += 1
project_indegree = collections.defaultdict(int)
group_indegree = collections.defaultdict(int)
project_neighbors = collections.defaultdict(list)
group_neighbors = collections.defaultdict(list)
group_projects = collections.defaultdict(list)
for project in range(n):
group_projects[group[project]].append(project)
for pre in pres[project]:
if group[pre] != group[project]:
# 小组关系图
group_indegree[group[project]] += 1
group_neighbors[group[pre]].append(group[project])
else:
# 项目关系图
project_indegree[project] += 1
project_neighbors[pre].append(project)
ans = []
group_queue = self.tp_sort([i for i in range(max_group_id)], group_indegree, group_neighbors)
if len(group_queue) != max_group_id:
return []
for group_id in group_queue:
project_queue = self.tp_sort(group_projects[group_id], project_indegree, project_neighbors)
if len(project_queue) != len(group_projects[group_id]):
return []
ans += project_queue
return ans
"" class Solution: def topological_sort(self,items,indegree,neighbors):
queue = collections.deque()
res = []
# 初始化队列
for item in items:
if not indegree[item]:
queue.append(item)
if not queue: return []
# BFS
while queue:
cur = queue.popleft()
res.append(cur)
# 遍历邻居节点
for neighbor in neighbors[cur]:
indegree[neighbor] -= 1
if not indegree[neighbor]:
queue.append(neighbor)
return res
def sortItems(self, n: int, m: int, group: List[int], beforeItems: List[List[int]]) -> List[int]:
max_group_id = m
for task in range(n):
if group[task] == -1:
group[task] = max_group_id
max_group_id += 1
task_indegree = [0] * n
group_indegree = [0] * max_group_id
task_neighbors = [[] for _ in range(n)]
group_neighbors = [[] for _ in range(max_group_id)]
group_to_tasks = [[] for _ in range(max_group_id)]
for task in range(n):
group_to_tasks[group[task]].append(task)
for prerequisite in beforeItems[task]:
# 判断相关联的两个项目是否属于同一组
if group[prerequisite] != group[task]:
# 不是同组,给小组建图
group_indegree[group[task]] += 1
group_neighbors[group[prerequisite]].append(group[task])
else:
# 同组,给组内项目建图
task_indegree[task] += 1
task_neighbors[prerequisite].append(task)
res = []
# 得到小组的访问顺序
group_queue = self.topological_sort([i for i in range(max_group_id)],group_indegree,group_neighbors)
if len(group_queue) != max_group_id: return []
for group_id in group_queue:
# 得到每组项目的访问顺序
task_queue = self.topological_sort(group_to_tasks[group_id],task_indegree,task_neighbors)
if len(task_queue) != len(group_to_tasks[group_id]):
return []
res += task_queue
return res
""
class Solution: def sortItems(self, n: int, m: int, group: List[int], beforeItems: List[List[int]]) -> List[int]: dep = [0] n # 项目依赖数,为0时,该项目才能执行 group_dep = [0] m # 小组依赖数(小组管理的所有项目的依赖总数),为0时,该小组才能开始执行项目 other_queue = [] # 暂无分组的子队列 groupqueue = [[] for in range(m)] # 各组的子队列 queuequeue = [] # 组队列,控制组与组之间的执行顺序,因为每个组的项目要一起执行 dependedBy = [[] for in range(n)] # 项目间的具体依赖
for i, l in enumerate(beforeItems):
dep[i] = len(l)
gi = group[i] # 项目i对应的组号
# 项目i没有依赖的项目,直接入队,准备执行
if not l:
(group_queue[gi] if gi != -1 else other_queue).append(i)
# 遍历项目i的依赖项目
for j in l:
# j是i的依赖
dependedBy[j].append(i)
# 项目i有已知分组,且没有形成了环,小组依赖数增加1
if gi != -1 and group[j] != gi:
group_dep[gi] += 1
# 初始化组队列,组队列的每个元素就是对应小组的子队列
for i, gd in enumerate(group_dep):
if not gd:
queue_queue.append(group_queue[i])
result = [] # 存储结果的列表
while True:
# 取出当前执行任务的小组,优先是有分组的
if queue_queue:
current_queue = queue_queue.pop()
elif other_queue:
current_queue = other_queue
else:
# 不能形成有效的序列,直接返回[]
if len(result) < n:
return []
# 可以形成有效的序列,返回result
else:
return result
# 遍历当前组的子队列
while current_queue:
p = current_queue.pop() # 项目p
result.append(p) # 项目p执行
gp = group[p] # 执行项目p的组号
# 遍历所有依赖p的项目(即p执行了,这些才能执行)
for i in dependedBy[p]:
gi = group[i] # 项目i的组号
dep[i] -= 1 # 依赖数减一
# 没有依赖了,可以入队准备执行
if not dep[i]:
(group_queue[gi] if gi != -1 else other_queue).append(i)
# 项目i有已知分组,且没有形成了环
if gi != -1 and gi != gp:
group_dep[gi] -= 1 # 组依赖数减一
# 没有依赖了,该组可以开始执行
if not group_dep[gi]:
queue_queue.append(group_queue[gi])
class Solution {
public int[] sortItems(int n, int m, int[] group, List<List<Integer>> beforeItems) {
Map<Integer, Integer> groupIndegree = new HashMap<>(); // <GroupId: Indegree of groupId>
Map<Integer, Integer> memberIndegree = new HashMap<>(); /// <MemberId: Indegree of memberId>
Map<Integer, List<Integer>> groupMember = new HashMap<>(); // <GroupId: List of memberIds in the group>
Map<Integer, Set<Integer>> groupGraph = new HashMap<>(); // <GroupId: List of groupIds that have to go after>
Map<Integer, List<Integer>> memberGraph = new HashMap<>(); // <MemberId: List of memberIds that have to go after>
// if a group is -1 change it to -i-1;
for (int i = 0; i < n; i++) {
if (group[i] < 0) {
group[i] = - i - 1;
}
groupIndegree.put(group[i], 0);
groupGraph.putIfAbsent(group[i], new HashSet<>());
groupMember.putIfAbsent(group[i], new ArrayList<>());
groupMember.get(group[i]).add(i);
}
for (int i = 0; i < n; i++) {
memberGraph.putIfAbsent(i, new ArrayList<>());
memberIndegree.put(i, beforeItems.get(i).size());
for (int before : beforeItems.get(i)) {
memberGraph.putIfAbsent(before, new ArrayList<>());
memberGraph.get(before).add(i);
if (group[before] != group[i] && groupGraph.get(group[before]).add(group[i])) {
groupIndegree.put(group[i], groupIndegree.get(group[i]) + 1);
}
}
}
// topological sort on the group first.
Deque<Integer> groupQ = new ArrayDeque<>();
Deque<Integer> memberQ = new ArrayDeque<>();
for (int g : groupIndegree.keySet()) {
if (groupIndegree.get(g) == 0) groupQ.addLast(g);
}
int[] res = new int[n];
int k = 0;
while (!groupQ.isEmpty()) {
int curGroup = groupQ.removeFirst();
// For each group, topological sort the members in the group.
for (int member : groupMember.get(curGroup)) {
if (memberIndegree.get(member) == 0) {
memberQ.add(member);
}
}
int count = 0;
while (!memberQ.isEmpty()) {
int member = memberQ.removeFirst();
res[k++] = member;
count++;
for (int nextMember : memberGraph.get(member)) {
memberIndegree.put(nextMember, memberIndegree.get(nextMember) - 1);
if (group[nextMember] == g && memberIndegree.get(nextMember) == 0) {
memberQ.addLast(nextMember);
}
}
}
if (count < groupMember.get(curGroup).size()) break;
for (int nextGroup : groupGraph.get(curGroup)) {
groupIndegree.put(nextGroup, groupIndegree.get(nextGroup) - 1);
if (groupIndegree.get(nextGroup) == 0) groupQ.addLast(nextGroup);
}
}
if (k < n) return new int[0];
return res;
}
}
/**
https://leetcode-cn.com/problems/sort-items-by-groups-respecting-dependencies/solution/chao-xiang-xi-shuang-ceng-tuo-bu-pai-xu-5cyuc/
*/
public class 项目管理_1203 {
// n 个项目 m个小组 每个项目属于哪个小组 下标i之前必须有哪些项目先做完
public int[] sortItems(int n, int m, int[] group, List<List
for(int i = 0; i < m + n; i++)
groupList.add(new ArrayList<>());
for(int i = 0; i < m + n; i++)
groupIds.add(i);
int newGroupNo = m;
for(int i = 0; i < n; i++) {
if(group[i] == -1) group[i] = newGroupNo++;
groupList.get(group[i]).add(i); // 归类到组号表中
}
List<List<Integer>> groupGraph = new ArrayList<>(); // 组依赖 依赖于idx 完成的组列表
List<List<Integer>> itemGraph = new ArrayList<>(); // 项目依赖
// 初始化
for(int i = 0; i < m + n; i++)
groupGraph.add(new ArrayList<>());
for(int i = 0; i < n; i++)
itemGraph.add(new ArrayList<>());
int[] groupIndegree = new int[m + n]; // 组的入度 因为 题中 “存在小组不负责任何项目,即没有任何项目属于这个小组” 传入的m组可能都是空组 入度需要 + m https://leetcode-cn.com/problems/sort-items-by-groups-respecting-dependencies/solution/chao-xiang-xi-shuang-ceng-tuo-bu-pai-xu-5cyuc/
int[] itemIndegree = new int[n]; // 项目的入度
for (int i = 0; i < n; i++) {
int groupId = group[i]; // 当前项目组号
List<Integer> depends = beforeItems.get(i); // 当前项目 的依赖表
for (int depend : depends) {
int dependGroupId = group[depend];
if(groupId == dependGroupId) {
// 相同的组 更新组内依赖
itemGraph.get(depend).add(i); // depend 指向 i
itemIndegree[i] ++; // 增加 i的入度
} else {
groupGraph.get(dependGroupId).add(groupId); // 组间 dependGroup 指向 本 group
groupIndegree[groupId] ++; // 增加group的入度
}
}
}
// 组间依赖是否成环 不成环输出组号列表
List<Integer> sortedGroupId = topSort(groupIndegree, groupGraph, groupIds);
if(sortedGroupId == null) return new int[0]; // new int[0] 表示空数组对象
// 组内依赖是否成环 不成环把每个组成员依次写到返回里
int[] res = new int[n];
int index = 0;
for (int groupId : sortedGroupId) {
List<Integer> inners = groupList.get(groupId); // 通过组号拿组内元素
List<Integer> sortedInners = topSort(itemIndegree, itemGraph, inners); // 组内排序
if(sortedInners == null) return new int[0]; // new int[0] 表示空数组对象
for(Integer item : sortedInners) {
res[index++] = item;
}
}
return res;
}
// 因为degree不一定对应nos中所有的no 可能有些不用 只需要排序 nos中的编号列表即可
// 拓扑排序 入度表 后续节点表 编号表
private List
/**
* @param {number} n
* @param {number} m
* @param {number[]} group
* @param {number[][]} beforeItems
* @return {number[]}
*/
var sortItems = function(n, m, group, beforeItems) {
const grahG = [], degG = new Uint16Array(n + m), idsG = [],
grahI = [], degI = new Uint16Array(n), idsI = [], r = []
for (let i = 0; i < n; i++) {
if (group[i] === -1) {
idsG[m] = m
group[i] = m++
} else idsG[group[i]] = group[i]
if (!idsI[group[i]]) idsI[group[i]] = []
idsI[group[i]].push(i)
}
for (let i = 0; i < n; i++) {
for (let j = 0; j < beforeItems[i].length; j++) {
const itemI = beforeItems[i][j]
if (group[i] === group[itemI]) {
degI[i]++
if (!grahI[itemI]) grahI[itemI] = []
grahI[itemI].push(i)
} else {
degG[group[i]]++
if (!grahG[group[itemI]]) grahG[group[itemI]] = []
grahG[group[itemI]].push(group[i])
}
}
}
// 组排序
const idsGS = sort(idsG.filter(v => v !== void 0), grahG, degG)
if (idsGS.length === 0) return []
for (let i = 0; i < idsGS.length; i++) {
if (!idsI[idsGS[i]]) continue
const idsIS = sort(idsI[idsGS[i]], grahI, degI)
if (idsIS.length === 0) return []
r.push(...idsIS)
}
return r
};
// 排序
const sort = (ids, grah, deg) => {
const q = [], r = []
let start = 0
for (let i = 0; i < ids.length; i++) if (deg[ids[i]] === 0) q.push(ids[i])
while (start < q.length) {
const n = q[start++]
r.push(n)
if (!grah[n]) continue
for (let i = 0; i < grah[n].length; i++) if (--deg[grah[n][i]] === 0) q.push(grah[n][i])
}
return r.length === ids.length ? r : []
}
放弃治疗
class Solution:
def tp_sort(self, items, indegree, neighbors):
q = collections.deque([])
ans = []
for item in items:
if not indegree[item]:
q.append(item)
while q:
cur = q.popleft()
ans.append(cur)
for neighbor in neighbors[cur]:
indegree[neighbor] -= 1
if not indegree[neighbor]:
q.append(neighbor)
return ans
def sortItems(self, n: int, m: int, group: List[int], pres: List[List[int]]) -> List[int]:
max_group_id = m
for project in range(n):
if group[project] == -1:
group[project] = max_group_id
max_group_id += 1
project_indegree = collections.defaultdict(int)
group_indegree = collections.defaultdict(int)
project_neighbors = collections.defaultdict(list)
group_neighbors = collections.defaultdict(list)
group_projects = collections.defaultdict(list)
for project in range(n):
group_projects[group[project]].append(project)
for pre in pres[project]:
if group[pre] != group[project]:
# 小组关系图
group_indegree[group[project]] += 1
group_neighbors[group[pre]].append(group[project])
else:
# 项目关系图
project_indegree[project] += 1
project_neighbors[pre].append(project)
ans = []
group_queue = self.tp_sort([i for i in range(max_group_id)], group_indegree, group_neighbors)
if len(group_queue) != max_group_id:
return []
for group_id in group_queue:
project_queue = self.tp_sort(group_projects[group_id], project_indegree, project_neighbors)
if len(project_queue) != len(group_projects[group_id]):
return []
ans += project_queue
return ans
时间复杂度:O(M+N)
空间复杂度:O(M+N)
/**
* @param {number} n
* @param {number} m
* @param {number[]} group
* @param {number[][]} beforeItems
* @return {number[]}
*/
var sortItems = function(n, m, group, beforeItems) {
const grahG = [], degG = new Uint16Array(n + m), idsG = [],
grahI = [], degI = new Uint16Array(n), idsI = [], r = []
for (let i = 0; i < n; i++) {
if (group[i] === -1) {
idsG[m] = m
group[i] = m++
} else idsG[group[i]] = group[i]
if (!idsI[group[i]]) idsI[group[i]] = []
idsI[group[i]].push(i)
}
for (let i = 0; i < n; i++) {
for (let j = 0; j < beforeItems[i].length; j++) {
const itemI = beforeItems[i][j]
if (group[i] === group[itemI]) {
degI[i]++
if (!grahI[itemI]) grahI[itemI] = []
grahI[itemI].push(i)
} else {
degG[group[i]]++
if (!grahG[group[itemI]]) grahG[group[itemI]] = []
grahG[group[itemI]].push(group[i])
}
}
}
// 组排序
const idsGS = sort(idsG.filter(v => v !== void 0), grahG, degG)
if (idsGS.length === 0) return []
for (let i = 0; i < idsGS.length; i++) {
if (!idsI[idsGS[i]]) continue
const idsIS = sort(idsI[idsGS[i]], grahI, degI)
if (idsIS.length === 0) return []
r.push(...idsIS)
}
return r
};
const sort = (ids, grah, deg) => {
const q = [], r = []
let start = 0
for (let i = 0; i < ids.length; i++) if (deg[ids[i]] === 0) q.push(ids[i])
while (start < q.length) {
const n = q[start++]
r.push(n)
if (!grah[n]) continue
for (let i = 0; i < grah[n].length; i++) if (--deg[grah[n][i]] === 0) q.push(grah[n][i])
}
return r.length === ids.length ? r : []
}
class Solution {
public int[] sortItems(int n, int m, int[] group, List<List<Integer>> beforeItems) {
Map<Integer, Integer> indegreeMap = new HashMap();
Map<Integer, List<Integer>> graph = new HashMap<>();
Map<Integer, List<Integer>> groupMap = new HashMap<>();
Map<Integer, Integer> grpIndegreeMap = new HashMap();
Map<Integer, List<Integer>> grpGraph = new HashMap<>();
for (int i = 0; i < n; i++) {
indegreeMap.put(i, 0);
graph.put(i, new ArrayList<>());
}
int nextGrpId = m;
for (int i = 0; i < group.length; i++) {
if (group[i] == -1) {
group[i] = nextGrpId;
nextGrpId++;
}
if (groupMap.get(group[i]) == null) {
groupMap.put(group[i], new ArrayList<>());
}
groupMap.get(group[i]).add(i);
}
for (int i = 0; i < n; i++) {
List<Integer> beforeList = beforeItems.get(i);
if (beforeList != null) {
for (Integer id : beforeList) {
if (group[i] == group[id]) {
indegreeMap.put(i, indegreeMap.get(i) + 1);
graph.get(id).add(i);
}
}
}
}
Map<Integer, List<Integer>> sortedGroupItemMap = new HashMap<>();
for (int grpId : groupMap.keySet()) {
List<Integer> sortedGroupItem = topoLogicSort(groupMap.get(grpId), indegreeMap, graph);
if (sortedGroupItem.size() == 0) {
return new int[0];
}
sortedGroupItemMap.put(grpId, sortedGroupItem);
}
for (int grpId : group) {
grpIndegreeMap.put(grpId, 0);
}
for (int i = 0; i < n; i++) {
List<Integer> beforeList = beforeItems.get(i);
if (beforeList != null) {
for (Integer id : beforeList) {
if (group[i] != group[id]) {
grpIndegreeMap.put(group[i], grpIndegreeMap.getOrDefault(group[i], 0) + 1);
if (grpGraph.get(group[id]) == null) {
grpGraph.put(group[id], new ArrayList<>());
}
grpGraph.get(group[id]).add(group[i]);
}
}
}
}
List<Integer> grpIDs = new ArrayList<>(grpIndegreeMap.keySet());
List<Integer> sortedGrp = topoLogicSort(grpIDs, grpIndegreeMap, grpGraph);
List<Integer> tempList = new ArrayList<>();
for (int grpId : sortedGrp) {
tempList.addAll(sortedGroupItemMap.get(grpId));
}
int[] res = new int[tempList.size()];
for (int i = 0; i < tempList.size(); i++) {
res[i] = tempList.get(i);
}
return res;
}
private List<Integer> topoLogicSort(List<Integer> items, Map<Integer, Integer> indegreeMap, Map<Integer, List<Integer>> graph) {
Queue<Integer> q = new LinkedList<>();
for (int id : items) {
if (indegreeMap.get(id) == 0) {
q.add(id);
}
}
List<Integer> tempList = new ArrayList<>();
while (!q.isEmpty()) {
int curId = q.poll();
tempList.add(curId);
List<Integer> nextIDs = graph.get(curId);
if (nextIDs != null) {
for (Integer nextID : nextIDs) {
indegreeMap.put(nextID, indegreeMap.get(nextID) - 1);
if (indegreeMap.get(nextID) == 0) {
q.add(nextID);
}
}
}
}
if (tempList.size() != items.size()) {
return new ArrayList<>();
}
return tempList;
}
}
import java.util.ArrayList; import java.util.HashMap; import java.util.LinkedList; import java.util.List; import java.util.Map; import java.util.Queue;
public 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;
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 (int beforeItem : beforeItems.get(i)) {
int beforeGroup = group[beforeItem];
if (beforeGroup != currentGroup) {
groupAdj[beforeGroup].add(currentGroup);
groupsIndegree[currentGroup]++;
}
}
}
for (int i = 0; i < n; i++) {
for (Integer item : beforeItems.get(i)) {
itemAdj[item].add(i);
itemsIndegree[i]++;
}
}
List<Integer> groupsList = topologicalSort(groupAdj, groupsIndegree, m);
if (groupsList.size() == 0) {
return new int[0];
}
List<Integer> itemsList = topologicalSort(itemAdj, itemsIndegree, n);
if (itemsList.size() == 0) {
return new int[0];
}
// 第 5 步:根据项目的拓扑排序结果,项目到组的多对一关系,建立组到项目的一对多关系
// key:组,value:在同一组的项目列表
Map<Integer, List<Integer>> groups2Items = new HashMap<>();
for (Integer item : itemsList) {
groups2Items.computeIfAbsent(group[item], key -> new ArrayList<>()).add(item);
}
List<Integer> res = new ArrayList<>();
for (Integer groupId : groupsList) {
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 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 (int successor : adj[front]) {
inDegree[successor]--;
if (inDegree[successor] == 0) {
queue.offer(successor);
}
}
}
if (res.size() == n) {
return res;
}
return new ArrayList<>();
}
}
下次一定,题解都看不懂
class Solution:
def tp_sort(self, items, indegree, neighbors):
q = collections.deque([])
ans = []
for item in items:
if not indegree[item]:
q.append(item)
while q:
cur = q.popleft()
ans.append(cur)
for neighbor in neighbors[cur]:
indegree[neighbor] -= 1
if not indegree[neighbor]:
q.append(neighbor)
return ans
def sortItems(self, n: int, m: int, group: List[int], pres: List[List[int]]) -> List[int]:
max_group_id = m
for project in range(n):
if group[project] == -1:
group[project] = max_group_id
max_group_id += 1
project_indegree = collections.defaultdict(int)
group_indegree = collections.defaultdict(int)
project_neighbors = collections.defaultdict(list)
group_neighbors = collections.defaultdict(list)
group_projects = collections.defaultdict(list)
for project in range(n):
group_projects[group[project]].append(project)
for pre in pres[project]:
if group[pre] != group[project]:
# 小组关系图
group_indegree[group[project]] += 1
group_neighbors[group[pre]].append(group[project])
else:
# 项目关系图
project_indegree[project] += 1
project_neighbors[pre].append(project)
ans = []
group_queue = self.tp_sort([i for i in range(max_group_id)], group_indegree, group_neighbors)
if len(group_queue) != max_group_id:
return []
for group_id in group_queue:
project_queue = self.tp_sort(group_projects[group_id], project_indegree, project_neighbors)
if len(project_queue) != len(group_projects[group_id]):
return []
ans += project_queue
return ans
拓扑排序,BFS。分别对组和项目进行拓扑排序。然后根据组和项目的一对多对应关系,合并成最终的拓扑排序结果。
class Solution {
public int[] sortItems(int n, int m, int[] group, List<List<Integer>> beforeItems) {
// 1. label the unassigned projects, group = -1
for (int i = 0; i < group.length; i++) {
if (group[i] == -1) {
group[i] = m;
m++;
}
}
// 2. initiate adjacent list for group and project
List<Integer>[] groupGraph = new ArrayList[m];
List<Integer>[] itemGraph = new ArrayList[n];
for (int i = 0; i < m; i++) groupGraph[i] = new ArrayList<>();
for (int i = 0; i < n; i++) itemGraph[i] = new ArrayList<>();
// 3. build graphs and get indegree information
int[] groupIndegree = new int[m];
int[] itemIndegree = new int[n];
int len = group.length; // m changed
for (int i = 0; i < len; i++) {
int curGroup = group[i];
for (int beforeItem: beforeItems.get(i)) {
int beforeGroup = group[beforeItem];
if (beforeGroup != curGroup) {
groupGraph[beforeGroup].add(curGroup);
groupIndegree[curGroup]++;
}
}
}
for (int i = 0; i < n; i++) {
for (int item: beforeItems.get(i)) {
itemGraph[item].add(i);
itemIndegree[i]++;
}
}
// 4. Get topo sort results
List<Integer> groupList = tpsort(groupGraph, groupIndegree, m);
if (groupList.size() == 0) return new int[0];
List<Integer> itemList = tpsort(itemGraph, itemIndegree, n);
if (itemList.size() == 0) return new int[0];
// 5. create map from group to project
Map<Integer, List<Integer>> map = new HashMap<>();
for (int item: itemList) {
map.computeIfAbsent(group[item], key -> new ArrayList<>()).add(item);
}
// 6. get the final project topo sort result
List<Integer> res = new ArrayList<>();
for (int groupId: groupList) {
List<Integer> items = map.getOrDefault(groupId, new ArrayList<>());
res.addAll(items);
}
return res.stream().mapToInt(Integer::valueOf).toArray();
}
private List<Integer> tpsort(List<Integer>[] graph, int[]indegree, int n) {
List<Integer> res = new ArrayList<>();
Deque<Integer> queue = new LinkedList<>();
for (int i = 0; i < n; i++) {
if (indegree[i] == 0) queue.offer(i);
}
while (!queue.isEmpty()) {
int node = queue.poll();
res.add(node);
for (int next: graph[node]) {
indegree[next]--;
if (indegree[next] == 0) {
queue.offer(next);
}
}
}
if (res.size() == n) return res;
return new ArrayList<>();
}
}
复杂度分析
https://leetcode-cn.com/problems/sort-items-by-groups-respecting-dependencies/
拓扑排序
class Solution:
def tp_sort(self, items, indegree, neighbors):
q = collections.deque([])
ans = []
for item in items:
if not indegree[item]:
q.append(item)
while q:
cur = q.popleft()
ans.append(cur)
for neighbor in neighbors[cur]:
indegree[neighbor] -= 1
if not indegree[neighbor]:
q.append(neighbor)
return ans
def sortItems(self, n: int, m: int, group: List[int], beforeItems: List[List[int]]) -> List[int]:
max_group_id = m
for project in range(n):
if group[project] == -1:
group[project] = max_group_id
max_group_id += 1
project_indegree = collections.defaultdict(int)
group_indegree = collections.defaultdict(int)
project_neighbors = collections.defaultdict(list)
group_neighbors = collections.defaultdict(list)
group_projects = collections.defaultdict(list)
for project in range(n):
group_projects[group[project]].append(project)
for pre in beforeItems[project]:
if group[pre] != group[project]:
group_indegree[group[project]] += 1
group_neighbors[group[pre]].append(group[project])
else:
project_indegree[project] += 1
project_neighbors[pre].append(project)
ans = []
group_queue = self.tp_sort([i for i in range(max_group_id)], group_indegree, group_neighbors)
if len(group_queue) != max_group_id:
return []
for group_id in group_queue:
project_queue = self.tp_sort(group_projects[group_id], project_indegree, project_neighbors)
if len(project_queue) != len(group_projects[group_id]):
return []
ans += project_queue
return ans
花了很久的时间的才弄懂题目的意思。然后默默去看大佬们的题解
1、 啥是拓步排序 2、 如何确定拓扑排序? 3、 项目和组的依赖关系、项目的顺序等 4、 无人负责的项目
JavaScript Code:
/**
* @param {number} n
* @param {number} m
* @param {number[]} group
* @param {number[][]} beforeItems
* @return {number[]}
*/
const topSort = (deg, graph, items) => {
const Q = [];
for (const item of items) {
if (deg[item] === 0) {
Q.push(item);
}
}
const res = [];
while (Q.length) {
const u = Q.shift();
res.push(u);
for (let i = 0; i < graph[u].length; ++i) {
const v = graph[u][i];
if (--deg[v] === 0) {
Q.push(v);
}
}
}
return res.length == items.length ? res : [];
}
var sortItems = function(n, m, group, beforeItems) {
const groupItem = new Array(n + m).fill(0).map(() => []);
// 组间和组内依赖图
const groupGraph = new Array(n + m).fill(0).map(() => []);
const itemGraph = new Array(n).fill(0).map(() => []);
// 组间和组内入度数组
const groupDegree = new Array(n + m).fill(0);
const itemDegree = new Array(n).fill(0);
const id = new Array(n + m).fill(0).map((v, index) => index);
let leftId = m;
// 给未分配的 item 分配一个 groupId
for (let i = 0; i < n; ++i) {
if (group[i] === -1) {
group[i] = leftId;
leftId += 1;
}
groupItem[group[i]].push(i);
}
// 依赖关系建图
for (let i = 0; i < n; ++i) {
const curGroupId = group[i];
for (const item of beforeItems[i]) {
const beforeGroupId = group[item];
if (beforeGroupId === curGroupId) {
itemDegree[i] += 1;
itemGraph[item].push(i);
} else {
groupDegree[curGroupId] += 1;
groupGraph[beforeGroupId].push(curGroupId);
}
}
}
// 组间拓扑关系排序
const groupTopSort = topSort(groupDegree, groupGraph, id);
if (groupTopSort.length == 0) {
return [];
}
const ans = [];
// 组内拓扑关系排序
for (const curGroupId of groupTopSort) {
const size = groupItem[curGroupId].length;
if (size == 0) {
continue;
}
const res = topSort(itemDegree, itemGraph, groupItem[curGroupId]);
if (res.length === 0) {
return [];
}
for (const item of res) {
ans.push(item);
}
}
return ans;
};
建图+拓扑排序
class Solution:
def topological_sort(self,items,indegree,neighbors):
# 建立队列和访问顺序
queue = collections.deque()
res = []
# 初始化队列
for item in items:
if not indegree[item]:
queue.append(item)
if not queue: return []
# BFS
while queue:
cur = queue.popleft()
res.append(cur)
# 遍历邻居节点
for neighbor in neighbors[cur]:
indegree[neighbor] -= 1
if not indegree[neighbor]:
queue.append(neighbor)
return res
def sortItems(self, n: int, m: int, group: List[int], beforeItems: List[List[int]]) -> List[int]:
max_group_id = m
for task in range(n):
if group[task] == -1:
group[task] = max_group_id
max_group_id += 1
task_indegree = [0] * n
group_indegree = [0] * max_group_id
task_neighbors = [[] for _ in range(n)]
group_neighbors = [[] for _ in range(max_group_id)]
group_to_tasks = [[] for _ in range(max_group_id)]
for task in range(n):
group_to_tasks[group[task]].append(task)
for prerequisite in beforeItems[task]:
# 判断相关联的两个项目是否属于同一组
if group[prerequisite] != group[task]:
# 不是同组,给小组建图
group_indegree[group[task]] += 1
group_neighbors[group[prerequisite]].append(group[task])
else:
# 同组,给组内项目建图
task_indegree[task] += 1
task_neighbors[prerequisite].append(task)
res = []
# 得到小组的访问顺序
group_queue = self.topological_sort([i for i in range(max_group_id)],group_indegree,group_neighbors)
if len(group_queue) != max_group_id: return []
for group_id in group_queue:
# 得到每组项目的访问顺序
task_queue = self.topological_sort(group_to_tasks[group_id],task_indegree,task_neighbors)
if len(task_queue) != len(group_to_tasks[group_id]):
return []
res += task_queue
return res
拓扑排序
class Solution {
public int[] sortItems(int n, int m, int[] group, List<List<Integer>> beforeItems) {
List<List<Integer>> groupItem = new ArrayList<List<Integer>>();
for (int i = 0; i < n + m; ++i) {
groupItem.add(new ArrayList<Integer>());
}
List<List<Integer>> groupGraph = new ArrayList<List<Integer>>();
for (int i = 0; i < n + m; ++i) {
groupGraph.add(new ArrayList<Integer>());
}
List<List<Integer>> itemGraph = new ArrayList<List<Integer>>();
for (int i = 0; i < n; ++i) {
itemGraph.add(new ArrayList<Integer>());
}
int[] groupDegree = new int[n + m];
int[] itemDegree = new int[n];
List<Integer> id = new ArrayList<Integer>();
for (int i = 0; i < n + m; ++i) {
id.add(i);
}
int leftId = m;
for (int i = 0; i < n; ++i) {
if (group[i] == -1) {
group[i] = leftId;
leftId += 1;
}
groupItem.get(group[i]).add(i);
}
for (int i = 0; i < n; ++i) {
int curGroupId = group[i];
for (int item : beforeItems.get(i)) {
int beforeGroupId = group[item];
if (beforeGroupId == curGroupId) {
itemDegree[i] += 1;
itemGraph.get(item).add(i);
} else {
groupDegree[curGroupId] += 1;
groupGraph.get(beforeGroupId).add(curGroupId);
}
}
}
List<Integer> groupTopSort = topSort(groupDegree, groupGraph, id);
if (groupTopSort.size() == 0) {
return new int[0];
}
int[] ans = new int[n];
int index = 0;
for (int curGroupId : groupTopSort) {
int size = groupItem.get(curGroupId).size();
if (size == 0) {
continue;
}
List<Integer> res = topSort(itemDegree, itemGraph, groupItem.get(curGroupId));
if (res.size() == 0) {
return new int[0];
}
for (int item : res) {
ans[index++] = item;
}
}
return ans;
}
public List<Integer> topSort(int[] deg, List<List<Integer>> graph, List<Integer> items) {
Queue<Integer> queue = new LinkedList<Integer>();
for (int item : items) {
if (deg[item] == 0) {
queue.offer(item);
}
}
List<Integer> res = new ArrayList<Integer>();
while (!queue.isEmpty()) {
int u = queue.poll();
res.add(u);
for (int v : graph.get(u)) {
if (--deg[v] == 0) {
queue.offer(v);
}
}
}
return res.size() == items.size() ? res : new ArrayList<Integer>();
}
}
Algo
- NEED REVISE!!!!!
class Solution:
def tp_sort(self, items, indegree, neighbors):
q = collections.deque([])
ans = []
for item in items:
if not indegree[item]:
q.append(item)
while q:
cur = q.popleft()
ans.append(cur)
for neighbor in neighbors[cur]:
indegree[neighbor] -= 1
if not indegree[neighbor]:
q.append(neighbor)
return ans
def sortItems(self, n: int, m: int, group: List[int], pres: List[List[int]]) -> List[int]:
max_group_id = m
for project in range(n):
if group[project] == -1:
group[project] = max_group_id
max_group_id += 1
project_indegree = collections.defaultdict(int)
group_indegree = collections.defaultdict(int)
project_neighbors = collections.defaultdict(list)
group_neighbors = collections.defaultdict(list)
group_projects = collections.defaultdict(list)
for project in range(n):
group_projects[group[project]].append(project)
for pre in pres[project]:
if group[pre] != group[project]:
group_indegree[group[project]] += 1
group_neighbors[group[pre]].append(group[project])
else:
project_indegree[project] += 1
project_neighbors[pre].append(project)
ans = []
group_queue = self.tp_sort([i for i in range(max_group_id)], group_indegree, group_neighbors)
if len(group_queue) != max_group_id:
return []
for group_id in group_queue:
project_queue = self.tp_sort(group_projects[group_id], project_indegree, project_neighbors)
if len(project_queue) != len(group_projects[group_id]):
return []
ans += project_queue
return ans
1203. 项目管理
入选理由
暂无
题目地址
https://leetcode-cn.com/problems/sort-items-by-groups-respecting-dependencies/
前置知识
题目描述
公司共有 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] 示例 2:
输入:n = 8, m = 2, group = [-1,-1,1,0,0,1,0,-1], beforeItems = [[],[6],[5],[6],[3],[],[4],[]] 输出:[] 解释:与示例 1 大致相同,但是在排序后的列表中,4 必须放在 6 的前面。
提示:
1 <= m <= n <= 3 * 104 group.length == beforeItems.length == n -1 <= group[i] <= m - 1 0 <= beforeItems[i].length <= n - 1 0 <= beforeItems[i][j] <= n - 1 i != beforeItems[i][j] beforeItems[i] 不含重复元素