Open azl397985856 opened 2 years ago
C++ Code:
class Solution {
public:
vector<int> topologicalSort(vector<vector<int>> &Adj, vector<int> &Indegree, int n){
vector<int> res;
queue<int> q;
for(int i = 0;i<n;i++){
if(Indegree[i]==0){
q.push(i);
}
}
while(!q.empty()){
int front = q.front();
q.pop();
res.push_back(front);
for(int successor: Adj[front]){
Indegree[successor]--;
if(Indegree[successor]==0){
q.push(successor);
}
}
}
if(res.size()==n){return res;}
return vector<int>();
}
vector<int> sortItems(int n, int m, vector<int>& group, vector<vector<int>>& beforeItems) {
for(int i=0;i<group.size();i++){
if(group[i] == -1){
group[i] = m;
m++;
}
}
vector<vector<int>> groupAdj(m, vector<int>());
vector<vector<int>> itemAdj(n, vector<int>());
vector<int> groupsIndegree(m, 0);
vector<int> itemIndegree(n, 0);
int len = group.size();
for(int i=0;i<len;i++){
int currentGroup = group[i];
for(int beforeItem: beforeItems[i]){
int beforeGroup = group[beforeItem];
if(beforeGroup!=currentGroup){
groupAdj[beforeGroup].push_back(currentGroup);
groupsIndegree[currentGroup]++;
}
}
}
for(int i=0;i<n;i++){
for(int item: beforeItems[i]){
itemAdj[item].push_back(i);
itemIndegree[i]++;
}
}
vector<int> groupList = topologicalSort(groupAdj, groupsIndegree, m);
if(groupList.size()==0){
return vector<int> ();
}
vector<int> itemList = topologicalSort(itemAdj, itemIndegree, n);
if(itemList.size()==0){
return vector<int> ();
}
map<int, vector<int>> group2Items;
for(int item: itemList){
group2Items[group[item]].push_back(item);
}
vector<int> res;
for(int groupId: groupList){
vector<int> items = group2Items[groupId];
for(int item: items){
res.push_back(item);
}
}
return res;
}
};
class Solution {
public int[] sortItems(int n, int m, int[] group, List<List<Integer>> beforeItems) {
// 1. 数据预先处理, 给没有分组的项目排到m组以后
for (int i = 0; i < group.length; i++) {
if(group[i] == -1){
group[i] = m;
m++;
}
}
// 2. 实现组和项目的有向图, 实现邻接表
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<>();
}
// 3. 建图和统计入度数组
int[] groupIndegree = 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);
groupIndegree[currentGroup]++;
}
}
}
// 项目
for (int i = 0; i < n; i++) {
for(Integer item : beforeItems.get(i)){
// 项目邻接表
itemAdj[item].add(i);
// items的入度+1
itemsIndegree[i]++;
}
}
// 4. 得到组和项目的拓扑排序
List<Integer> groupList = topologicalSort(groupAdj, groupIndegree,m);
if(groupList.size() == 0){
return new int[0];
}
List<Integer> itemList = topologicalSort(itemAdj, itemsIndegree, n);
if(itemList.size() == 0){
return new int[0];
}
// 5. 根据项目的拓扑排序结果,项目到组的多对一关系,建立组到项目的一对多关系
// key: 组, value: 在同一组的项目项目
Map<Integer, List<Integer>> groups2Items = new HashMap<>();
for (Integer item: itemList){
groups2Items.computeIfAbsent(group[item], key -> new ArrayList<>()).add(item);
}
// 6. 把组的拓扑排序结果替换成项目的拓扑排序结果
List<Integer> res = new ArrayList<>();
for (Integer groupId : groupList) {
List<Integer> items = groups2Items.getOrDefault(groupId, new ArrayList<>());
res.addAll(items);
}
// 转换成数组并返回
return res.stream().mapToInt(Integer::valueOf).toArray();
}
private List<Integer> topologicalSort(List<Integer>[] adj, int[] inDegree, int n) {
ArrayList<Integer> res = new ArrayList<>();
LinkedList<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]){
// 后继结点-1
inDegree[successor]--;
// 当入度为0时, 加入后继结点
if(inDegree[successor] == 0){
queue.offer(successor);
}
}
}
// 不存在环
if(res.size() == n){
return res;
}
// 存在环
return new ArrayList<>();
}
}
//拓扑排序
vector<int> topSort(vector<vector<int>>& graph, vector<int>& inDegree) {
vector<int> res;
queue<int> q;
//入度为0的结点入q
for (int i = 0; i < inDegree.size(); ++i) {
if (inDegree[i] == 0) {
q.emplace(i);
}
}
while (!q.empty()) {
int prerequisite = q.front();
q.pop();
res.emplace_back(prerequisite);
//相关结点入度-1
for (int n : graph[prerequisite]) {
//入度为0则加入队列
if (--inDegree[n] == 0) {
q.emplace(n);
}
}
}
//结果数组大小与结点数量一致表示无环
return res.size() == inDegree.size() ? res : vector<int>{};
}
vector<int> sortItems(int n, int m, vector<int>& group, vector<vector<int>>& beforeItems) {
// 组号为-1的项目彼此应属于不同组,且组号应与实际存在的组不同
for (int i = 0; i < group.size(); ++i) {
if (group[i] == -1) {
group[i] = m++;
}
}
vector<vector<int>> groupAdj(m);
vector<vector<int>> itemAdj(n);
vector<int> groupsIndegree(m);
vector<int> itemsIndegree(n);
//根据项目的约束间接找到组之间的约束,并建立组的邻接矩阵和入度统计数组
for (int i = 0; i < group.size(); ++i) {
int currentGroup = group[i];
for (int beforeItem : beforeItems[i]) {
//前置项目所在组
int beforeGroup = group[beforeItem];
//前置项目所在组与本项目所在组不同,则加入groupAdj中
if (beforeGroup != currentGroup) {
groupAdj[beforeGroup].emplace_back(currentGroup);
++groupsIndegree[currentGroup];
}
}
}
//根据项目约束,创建项目的邻接矩阵和入度统计数组
for (int i = 0; i < n; ++i) {
for (int item : beforeItems[i]) {
itemAdj[item].emplace_back(i);
++itemsIndegree[i];
}
}
//分别对group和item进行拓扑排序,检查是否存在环
vector<int> groupsList = topSort(groupAdj, groupsIndegree);
if (groupsList.size() == 0) {
return{};
}
vector<int> itemsList = topSort(itemAdj, itemsIndegree);
if (itemsList.size() == 0) {
return{};
}
// key:组号,value:该组的项目
unordered_map<int, vector<int>> groups2Items;
for (int item : itemsList) {
groups2Items[group[item]].emplace_back(item);
}
// 根据组的拓扑排序,通过查找组-项目hash表,按拓扑排序结果添加项目
vector<int> res;
for (int groupId : groupsList) {
vector<int> items = groups2Items[groupId];
res.insert(res.end(), items.begin(),items.end());
}
return res;
}
代码是看官方题解写的,当前只能说是理解了为什么这样写,但掌握还不敢说
Credit: Solution on YouTube
Language: Java
public int[] sortItems(int n, int m, int[] group, List<List<Integer>> beforeItems) {
// Assign a group number to items with no group. Assign them "m"
for (int i = 0; i < group.length; i++) {
if (group[i] == -1) {
group[i] = m;
m++;
}
}
// Instantiate adjacency lists fro groups and items
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<>();
}
// Construct graph
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]++;
}
}
// Topological sort on groups and items
List<Integer> groupsList = topologicalSort(groupAdj, groupsIndegree);
if (groupsList.size() == 0) {
return new int[0];
}
List<Integer> itemsList = topologicalSort(itemAdj, itemsIndegree);
if (itemsList.size() == 0) {
return new int[0];
}
// Create a map on group (key) and items (value) based on previous results
Map<Integer, List<Integer>> groups2Items = new HashMap<>();
for (Integer item : itemsList) {
groups2Items.computeIfAbsent(group[item], key -> new ArrayList<>()).add(item);
}
// Insert item sort result in group sort result to obtain final result
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) {
List<Integer> res = new ArrayList<>();
Queue<Integer> queue = new LinkedList<>();
for (int i = 0; i < adj.length; 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() == adj.length) {
return res;
}
return new ArrayList<>();
}
class Solution {
Map <Integer, List<Integer>> groupGraph;
Map <Integer, List<Integer>> itemGraph;
int[] groupsIndegree;
int[] itemsIndegree;
private void buildGraphOfGroups(int[] group, List<List<Integer>> beforeItems, int n) {
for (int i=0;i<group.length;i++) {
int toGroup = group[i];
List <Integer> fromItems = beforeItems.get(i);
for (int fromItem : fromItems) {
int fromGroup = group[fromItem];
if(fromGroup != toGroup) {
groupGraph.computeIfAbsent(fromGroup, x->new ArrayList()).add(toGroup);
groupsIndegree[toGroup]++;
}
}
}
}
private void buildGraphOfItems(List<List<Integer>> beforeItems, int n) {
for (int i=0;i<n;i++) {
List<Integer> items = beforeItems.get(i);
for (Integer item : items) {
itemGraph.computeIfAbsent(item, x->new ArrayList()).add(i);
itemsIndegree[i]++;
}
}
}
private List<Integer> topologicalSortUtil(Map <Integer, List<Integer>> graph, int[] indegree, int n) {
List <Integer> list = new ArrayList<Integer>();
Queue <Integer> queue = new LinkedList();
for (int key : graph.keySet()) {
if(indegree[key] == 0) {
queue.add(key);
}
}
while(!queue.isEmpty()) {
int node = queue.poll();
n--;
list.add(node);
for (int neighbor : graph.get(node)) {
indegree[neighbor] --;
if(indegree[neighbor] == 0) {
queue.offer(neighbor);
}
}
}
return n == 0 ? list : new ArrayList();
}
public int[] sortItems(int n, int m, int[] group, List<List<Integer>> beforeItems) {
groupGraph = new HashMap();
itemGraph = new HashMap();
for (int i=0;i<group.length;i++) {
if(group[i] == -1) group[i] = m++;
}
for (int i=0;i<m;i++) {
groupGraph.put(i, new ArrayList());
}
for (int i=0;i<n;i++) {
itemGraph.put(i, new ArrayList());
}
groupsIndegree = new int[m];
itemsIndegree = new int[n];
buildGraphOfGroups(group, beforeItems, n);
buildGraphOfItems(beforeItems, n);
List<Integer> groupsList = topologicalSortUtil(groupGraph, groupsIndegree, m);
List<Integer> itemsList = topologicalSortUtil(itemGraph, itemsIndegree, n);
if(groupsList.size() == 0 || itemsList.size() == 0) return new int[0];
Map <Integer, List<Integer>> groupsToItems = new HashMap();
for (Integer item : itemsList) {
groupsToItems.computeIfAbsent(group[item], x->new ArrayList()).add(item);
}
int[] ans = new int[n];
int idx = 0;
for (Integer grp : groupsList) {
List <Integer> items = groupsToItems.getOrDefault(grp, new ArrayList());
for (Integer item : items) {
ans[idx++] = item;
}
}
return ans;
}
}
图+hard 真的好难
下次一定
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<>();
}
}
先打个卡
class Solution:
def sortItems(self, n: int, m: int, group: List[int], beforeItems: List[List[int]]) -> List[int]:
def get_top_order(graph, indegree):
top_order = []
stack = [node for node in range(len(graph)) if indegree[node] == 0]
while stack:
v = stack.pop()
top_order.append(v)
for u in graph[v]:
indegree[u] -= 1
if indegree[u] == 0:
stack.append(u)
return top_order if len(top_order) == len(graph) else []
for u in range(len(group)):
if group[u] == -1:
group[u] = m
m+=1
graph_items = [[] for _ in range(n)]
indegree_items = [0] * n
graph_groups = [[] for _ in range(m)]
indegree_groups = [0] * m
for u in range(n):
for v in beforeItems[u]:
graph_items[v].append(u)
indegree_items[u] += 1
if group[u]!=group[v]:
graph_groups[group[v]].append(group[u])
indegree_groups[group[u]] += 1
item_order = get_top_order(graph_items, indegree_items)
group_order = get_top_order(graph_groups, indegree_groups)
if not item_order or not group_order: return []
order_within_group = collections.defaultdict(list)
for v in item_order:
order_within_group[group[v]].append(v)
res = []
for group in group_order:
res += order_within_group[group]
return res
javascript
/*
* @lc app=leetcode.cn id=1203 lang=javascript
*
* [1203] 项目管理
*/
// @lc code=start
/**
* @param {number} n
* @param {number} m
* @param {number[]} group
* @param {number[][]} beforeItems
* @return {number[]}
*/
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
};
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 : []
}
// @lc code=end
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
From the project, due to the existence of beforeItems list, this is a directed graph. To get its order, we will need topological sort to accomplish it. In the problems, items are split into group 0-- m-1 + ungrouped, so those ungrouped items should be renumbered first inorder to do correct tpSort group 0 ~ m-1 also has to be sorted So the approach is to tp sort group first and then use the order to tpsort items.
class Solution:
# tp sort for groups, then use the order to sort items
# tp sort -- BFS can work, use a helper function to do tpsort
def tpSort(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]:
"""step 1. re-numbering those items that are not in the group
since we have m group, the items not in group can be renumbering starting from m
"""
max_group_id = m
for project in range(n):
if group[project] == -1:
group[project] = max_group_id
max_group_id += 1
# create dictionary to store neighbors and indegree for tp sort purpose
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 items in two different groups
# we will create the group dependencies
if group[pre] != group[project]:
group_indegree[group[project]] += 1
group_neighbors[group[pre]].append(group[project])
else:
# if items in the same group
# we create item dependencies
project_indegree[project] += 1
project_neighbors[pre].append(project)
ans = []
# tp sort group + ungrouped items and then tp sort items
group_queue = self.tpSort([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.tpSort(group_projects[group_id], project_indegree, project_neighbors)
if len(project_queue) != len(group_projects[group_id]):
return []
ans += project_queue
return ans
one indegree array/map for project
one indegree array/map for group
m groups: 0-(m-1)
n items: 0-(n-1)
when a group == -1, start from m, increment its group id
5
3
[0,0,2,1,0]
[[3],[],[],[],[1,3,2]]
[3,2,0,1,4]
5
3
[0,0,2,1,0]
[[3],[],[],[],[1,3,2]]
-> [3,2,0,1,4]
do not double count duplicate edges for in-degree
Time: O(2*n) + O(maxGroupID) + O(n + number of pres) + O(maxGroupID) + O(number of groups + number of group edges) + O(number of item + number of item edge)
Space:
output: O(n)
Map<Integer, Set<Integer>> groupProjectsMapping: O(n)
Map<Integer, Set<Integer>> projectIndegree: O(n + edges between item)
Map<Integer, Set<Integer>> groupIndegree: O(group num + edge between group)
Map<Integer, Set<Integer>> groupsGraph: O(group num + edge between group), edge between group bounded by number of pres
Map<Integer, Set<Integer>> projectsGraph: O(n + edges between item)
Set<Integer> groupNodes: O(maxGroupID)
Set<Integer> targetNodes: O(n)
class Solution {
public int[] sortItems(int n, int m, int[] group, List<List<Integer>> beforeItems) {
int maxGroupID = m;
// reassign the group id given -1, -1 means an item stands on its own
for (int i = 0; i < n; i++) {
if (group[i] == -1) {
group[i] = maxGroupID;
maxGroupID++;
}
}
// assign each project to each group
// group -> set of projects
// & populate:
// one indegree array for project
// one indegree array for group
// & build 2 graphs: projects (pre) / groups -> neighbors 小组关系图 + 项目关系图
Map<Integer, Set<Integer>> groupProjectsMapping = new HashMap<>();
// project - indegree mapping
// do not double count duplicate edges for in-degree, that's why i don't use int[] here
Map<Integer, Set<Integer>> projectIndegree = new HashMap<>(); // max n size
for (int i = 0; i < n; i++) {
projectIndegree.put(i, new HashSet<>());
}
Map<Integer, Set<Integer>> groupIndegree = new HashMap<>(); // maxGroupID size
for (int i = 0; i < maxGroupID; i++) {
groupIndegree.put(i, new HashSet<>());
}
Map<Integer, Set<Integer>> groupsGraph = new HashMap<>();
Map<Integer, Set<Integer>> projectsGraph = new HashMap<>();
for (int p = 0; p < n; p++) {
int groupID = group[p];
if (!groupProjectsMapping.containsKey(groupID)) {
groupProjectsMapping.put(groupID, new HashSet<Integer>());
}
groupProjectsMapping.get(groupID).add(p);
// we can check the pre for each project
List<Integer> presOfP = beforeItems.get(p);
for (int preOfP : presOfP) {
int groupOfPre = group[preOfP];
int groupOfP = group[p];
// pre and p are not in the same group
if (groupOfPre != groupOfP) { // self-loop excluded
// pre's group goes before p's group, pre's group -> p's group
groupIndegree.get(groupOfP).add(groupOfPre);
if (!groupsGraph.containsKey(groupOfPre)) {
groupsGraph.put(groupOfPre, new HashSet<Integer>());
}
groupsGraph.get(groupOfPre).add(groupOfP);
}
// pre and p are in the same group
// 因为属于不同group的project,indegree不影响,所以如果pre和project在不同group,不需要更新project indegree(我之前问的else地方想明白了,# 项目关系图处)。
else { //最后按group,分别sort,然后append结果。所以project之间关系仅针对同一group更新即可
projectIndegree.get(p).add(preOfP);
if (!projectsGraph.containsKey(preOfP)) {
projectsGraph.put(preOfP, new HashSet<Integer>());
}
projectsGraph.get(preOfP).add(p);// inside projectsGraph, of course, neighbors are from the same group
}
}
}
//System.out.println(groupIndegree);
// after extracting all the info, call topological sorting on group
Set<Integer> groupNodes = new HashSet<>();
for (int i = 0; i < maxGroupID; i++) {
groupNodes.add(i);
}
List<Integer> sortGroupRes = topologicalSort(groupNodes, groupIndegree, groupsGraph);
// System.out.println(sortGroupRes);
if (sortGroupRes.size() != maxGroupID) {
return new int[0];
}
int[] sortRes = new int[n];
int index = 0;
// topological sort every single group
for (int groupID : sortGroupRes) {
Set<Integer> targetNodes = groupProjectsMapping.get(groupID);
if (targetNodes == null) continue; //A group can have no item belonging to it.
List<Integer> sortProjects = topologicalSort(targetNodes, projectIndegree, projectsGraph);
if (sortProjects.size() != targetNodes.size()) {
return new int[0];
}
for (int each : sortProjects) {
sortRes[index++] = each;
}
}
return sortRes;
}
// topological sort
private List<Integer> topologicalSort(Set<Integer> selectedNodes, Map<Integer, Set<Integer>> indegree, Map<Integer, Set<Integer>> graph) {
List<Integer> sortRes = new ArrayList<>();
Queue<Integer> queue = new LinkedList<>();
for (int id : selectedNodes) {
if (indegree.get(id).size() == 0) {
queue.offer(id);
}
}
while (!queue.isEmpty()) {
int curNode = queue.poll();
sortRes.add(curNode);
Set<Integer> neighbors = graph.get(curNode);
if (neighbors != null) {
for (int neighbor : neighbors) {
indegree.get(neighbor).remove(curNode);
if (indegree.get(neighbor).size() == 0) {
queue.offer(neighbor);
}
}
}
}
return sortRes;
}
}
拓扑排序。
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
根据题意思路是 两重拓扑排序, 对组之间和组内 根据 before 数组都进行拓扑排序
先给 group 标号为 -1 的标记为一个新的只有这个数的组, 方便下面的排序
然后构建 组内, 组间的 next 数组, 即 before 的相反方向的链接, 并添加 1 到 被指向的 node 的 indegree
先 topological sort 组, 如果返回 [] 代表不可能那么返回 []
再遍历每一个组, topological sort 每个组内的 elements, 如果返回 [] 代表不可能那么返回 []
最后将两次 topological sort 的结果拼接, 先遍历组 topological sort 的结果,再将这个组 topological sort 好的 elements 添加到 res 数组中
topological bfs algorithm:
先添加所有 indegree 为 0 的点到 queue 中
如果 queue 不是empty, 那么将 queue 左端元素 pop, 添加到 res 数组中, 然后 将 这个元素指向的元素 (即要求这个元素最为 before 的元素) 的 indegree -1
如果 -1 后这个元素的 indegree 是 0, 将这个元素 添加到 queue 中
最后如果 res 数组的长度 跟 element 数组的长度不同, 说明无法完成 topological sort, 那么返回 [], 否则返回 res 数组
import collections
from collections import deque
class Solution:
def sortItems(self, n: int, m: int, group: List[int], beforeItems: List[List[int]]) -> List[int]:
def topological_sort(graph_next, graph_indegree, graph_elements):
# bfs topological sort
queue = deque()
res = []
for i in graph_elements:
if graph_indegree[i] == 0:
queue.append(i)
while len(queue) > 0:
i = queue.popleft()
res.append(i)
for j in graph_next[i]:
graph_indegree[j] -= 1
if graph_indegree[j] == 0:
queue.append(j)
if len(res) != len(graph_elements):
return []
else:
return res
# for the ones in group -1, give a unique group id
for i in range(len(group)):
if group[i] == -1:
group[i] = m
m += 1
groupitem = collections.defaultdict(list)
# build the within group and between group graph and indegree
groupnext = collections.defaultdict(set)
itemnext = collections.defaultdict(set)
groupindegree = collections.defaultdict(int)
itemindegree = collections.defaultdict(int)
for i, before in enumerate(beforeItems):
gi = group[i]
groupitem[gi].append(i)
for j in before:
gj = group[j]
# if in same group, then build within in group topological sort
if group[i] == group[j]:
itemnext[j].add(i)
itemindegree[i] += 1
else:
# remove duplicate links in graph pointing from 1 part to another
if gi not in groupnext[gj]:
groupnext[gj].add(gi)
groupindegree[gi] += 1
# group topological sort
group_res = topological_sort(groupnext, groupindegree, list(range(m)))
if group_res == []:
return []
# item topological sort for each group
item_res = []
for i in range(m):
groupelements = groupitem[i]
i_res = topological_sort(itemnext, itemindegree, groupelements)
if len(groupelements) > 0 and i_res == []:
return []
item_res.append(i_res)
# put two topological result together into the order
res = []
for i in group_res:
res.extend(item_res[i])
return res
时间复杂度: O(m+n) 拓扑排序的时间复杂度
空间复杂度: O(m+n) 存储组间依赖和入读的复杂度, 是 O(m+n)
https://www.cnblogs.com/grandyang/p/15187461.html
class Solution {
public:
vector<int> sortItems(int n, int m, vector<int>& group, vector<vector<int>>& beforeItems) {
vector<int> t, res(n), state(n + 2 * m);
vector<vector<int>> g(n + 2 * m);
for (int i = 0; i < n; ++i) {
if (group[i] != -1) {
g[n + group[i]].push_back(i);
g[i].push_back(n + m + group[i]);
}
for (int j : beforeItems[i]) {
if (group[i] != -1 && group[i] == group[j]) {
g[j].push_back(i);
} else {
int p = group[i] == -1 ? i : n + group[i];
int q = group[j] == -1 ? j : n + m + group[j];
g[q].push_back(p);
}
}
}
for (int i = (int)g.size() - 1; i >= 0; --i) {
if (!helper(g, i, state, t)) return {};
}
reverse(t.begin(), t.end());
copy_if(t.begin(), t.end(), res.begin(), [&](int i) {return i < n;});
return res;
}
bool helper(vector<vector<int>>& g, int i, vector<int>& state, vector<int>& res) {
if (state[i] != 0) return state[i] == 2;
state[i] = 1;
for (int next : g[i]) {
if (!helper(g, next, state, res)) return false;
}
state[i] = 2;
res.push_back(i);
return true;
}
};
1203. 项目管理
入选理由
暂无
题目地址
https://leetcode-cn.com/problems/sort-items-by-groups-respecting-dependencies/
前置知识
- 图论
- 拓扑排序
- BFS & DFS
题目描述
公司共有 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] 不含重复元素
双层拓扑排序,先对小组排序,再对组内项目排序,同一个小组的项目连续完成。 代码虽长 但重复多 小组排序和项目排序几乎一样 变量命名时注意一致 避免迷糊
def sortItems2(n, m, group, beforeItems) # 为不属于任何小组的项目设置一个虚拟组名 j=m for i in range(n): if group[i]==-1: group[i]=j j+=1 # 小组拓扑:in={小组:需要排在前面的小组} out={小组:需要排在后面的小组} groups=list(set(group)) # 注意:使用set避免重复 group_in, group_out = defaultdict(set), defaultdict(set) for i in range(n): for pre_i in beforeItems[i]: if group[pre_i]!=group[i]: # 注意: 不等时才加入 group_in[group[i]].add(group[pre_i]) group_out[group[pre_i]].add(group[i]) indegree={g:len(group_in[g]) for g in groups} que=[g for g in groups if indegree[g]==0] order_group=[] while que: g = que.pop() order_group.append(g) for g_post in group_out[g]: indegree[g_post]-=1 if indegree[g_post]==0: que.append(g_post) if len(order_group)<len(groups): return [] # 建立字典 {小组: 组内项目} group_item=defaultdict(list) for i in range(len(group)): group_item[group[i]].append(i) # 组内项目拓扑排序 遍历小组按顺序执行 execute=[] for g in order_group: item_in, item_out = defaultdict(list), defaultdict(list) for i in group_item[g]: for pre_i in beforeItems[i]: if pre_i in group_item[g]: # 注意: 同一个组才加入 item_in[i].append(pre_i) item_out[pre_i].append(i) indegree={i:len(item_in[i]) for i in group_item[g]} que=[i for i in group_item[g] if indegree[i]==0] temp=[] while que: i = que.pop() temp.append(i) for i_post in item_out[i]: indegree[i_post]-=1 if indegree[i_post]==0: que.append(i_post) if len(temp)<len(group_item[g]): return [] execute+=temp return execute
时间复杂度: O(m+n)
空间复杂度: O(m+n)
class Solution(object):
def sortItems(self, n, m, group, beforeItems):
"""
:type n: int
:type m: int
:type group: List[int]
:type beforeItems: List[List[int]]
:rtype: 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
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
学习了拓扑排序
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 and
时间 O(m+n)
记录节点的依赖数,依赖数降到0时入队的方式。我们需要做到以下几点:
class Solution:
def sortItems(self, n: int, m: int, group: List[int], beforeItems: List[List[int]]) -> List[int]:
dep = [0] * n
group_dep = [0] * m
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]
for j in l:
dependedBy[j].append(i)
if gi != -1 and group[j] != gi:
group_dep[gi] += 1
if not l:
(group_queue[gi] if gi != -1 else other_queue).append(i)
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 []
else:
return result
while current_queue:
p = current_queue.pop()
result.append(p)
gp = group[p]
for i in dependedBy[p]:
gi = group[i]
dep[i] -= 1
if not dep[i]:
(group_queue[gi] if gi != -1 else other_queue).append(i)
if gi != -1 and gi != gp:
group_dep[gi] -= 1
if not group_dep[gi]:
queue_queue.append(group_queue[gi])
public class Solution {
public int[] sortItems(int n, int m, int[] group, List<List<Integer>> beforeItems) {
// 第 1 步:数据预处理,给没有归属于一个组的项目编上组号
for (int i = 0; i < group.length; i++) {
if (group[i] == -1) {
group[i] = m;
m++;
}
}
// 第 2 步:实例化组和项目的邻接表
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<>();
}
// 第 3 步:建图和统计入度数组
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]++;
}
}
// 第 4 步:得到组和项目的拓扑排序结果
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);
}
// 第 6 步:把组的拓扑排序结果替换成为项目的拓扑排序结果
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<>();
}
}
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 int[] sortItems(int n, int m, int[] group, List<List<Integer>> beforeItems) {
Map<Integer, Set<Integer>> groupGraph = new HashMap<>();
Map<Integer, Integer> indegreeGroup = new HashMap<>();
int increment = 0;
for(int i = 0 ; i < group.length; i++){
if(group[i]==-1){
group[i] = group[i] + increment;
increment = increment-2;
}
groupGraph.put(group[i], new HashSet<Integer>());
}
Map<Integer, Set<Integer>> itemGraph = new HashMap<>();
Map<Integer, Integer> indegreeItem = new HashMap<>();
for(int i = 0; i < n ; i++)
itemGraph.put(i, new HashSet<Integer>());
for(int i = 0 ; i < beforeItems.size(); i++){
List<Integer> l = beforeItems.get(i);
for(int item : l){
itemGraph.get(item).add(i);
indegreeItem.put(i, indegreeItem.getOrDefault(i,0)+1);
int group1 = group[item];
int group2 = group[i];
if(group1!=group2 && groupGraph.get(group1).add(group2)){
indegreeGroup.put(group2, indegreeGroup.getOrDefault(group2,0)+1);
}
}
}
List<Integer> itemOrdering = topoSort(itemGraph, indegreeItem, n);
List<Integer> groupOrdering = topoSort(groupGraph, indegreeGroup, groupGraph.size());
if(itemOrdering.size()==0 || groupOrdering.size()==0) return new int[0];
Map<Integer, List<Integer>> map = new HashMap<>();
for(int item : itemOrdering){
int grp = group[item];
map.putIfAbsent(grp, new ArrayList<>());
map.get(grp).add(item);
}
int[] res = new int[n];
int i=0;
for(int grp : groupOrdering){
List<Integer> l = map.get(grp);
for(int item : l){
res[i] = item;
i++;
}
}
return res;
}
private List<Integer> topoSort(Map<Integer, Set<Integer>> itemGraph,
Map<Integer, Integer> indegreeItem, int countOfItems) {
Queue<Integer> q = new LinkedList<>();
List<Integer> res = new ArrayList<>();
for(int i: itemGraph.keySet()){
if(indegreeItem.getOrDefault(i,0)==0)
q.add(i);
}
while(!q.isEmpty()){
int pop = q.poll();
countOfItems--;
res.add(pop);
for(int nextItem : itemGraph.get(pop)){
int indegreeOfNextItem = indegreeItem.get(nextItem)-1;
indegreeItem.put(nextItem, indegreeOfNextItem);
if(indegreeOfNextItem==0)
q.add(nextItem);
}
}
if(countOfItems==0) return res;
else return new ArrayList<>();
}
}
实现语言: C++
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;
// 给未分配的 item 分配一个 groupId
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;
}
};
做两次拓扑排序
目前还没理解,先来打卡~~
java
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<>();
}
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<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>(); } }
拓扑排序
Java Code:
class Solution {
public int[] sortItems(int n, int m, int[] group, List<List<Integer>> beforeItems) {
for(int i = 0; i < n; i++){
if(group[i] == -1) {
group[i] = m++;
}
}
int[] countsGroup = new int[m];
List<List<Integer>> graphGroups = buildGraphGroups(group, beforeItems, countsGroup, m, n);
int[] countsItem = new int[n];
List<List<Integer>> graphItems = buildGraphItems(beforeItems, countsItem, n);
// to acquire the topologically sorted groups and items
List<Integer> groupsSorted = topologicalSort(graphGroups, countsGroup);
List<Integer> itemsSorted = topologicalSort(graphItems, countsItem);
// to detect any cycle
if(groupsSorted.isEmpty() || itemsSorted.isEmpty()) return new int[0];
// to build up the relationship between sorted groups and sorted items
List<List<Integer>> groupsToItems = new ArrayList<List<Integer>>(m);
for(int i = 0; i < m; i++){
groupsToItems.add(new ArrayList<Integer>());
}
for(int item : itemsSorted){
groupsToItems.get(group[item]).add(item);
}
// to generate the answer array
int[] ans = new int[n];
int idx = 0;
// to first pick, in front groups, front elements/items
for(int curGroup : groupsSorted){
for(int item : groupsToItems.get(curGroup)) {
ans[idx++] = item;
}
}
return ans;
}
private List<Integer> topologicalSort(List<List<Integer>> graph, int[] counts){
final int N = counts.length;
List<Integer> res = new ArrayList<Integer>();
Queue<Integer> queue = new LinkedList<Integer>();
for(int i = 0; i < N; i++){
if(counts[i] == 0){
queue.add(i);
}
}
int count = 0;
while(!queue.isEmpty()){
int node = queue.poll();
res.add(node);
count++;
for(int neighbor : graph.get(node)){
if(--counts[neighbor] == 0){
queue.offer(neighbor);
}
}
}
return count == N ? res : new ArrayList<Integer>();
}
private List<List<Integer>> buildGraphItems(List<List<Integer>> beforeItems,
int[] counts,
int n){
List<List<Integer>> graph = new ArrayList<List<Integer>>();
for(int i = 0; i < n; i++){
graph.add(new ArrayList<Integer>());
}
for(int i = 0; i < n; i++){
List<Integer> items = beforeItems.get(i);
for(int item : items){
graph.get(item).add(i);
++counts[i];
}
}
return graph;
}
private List<List<Integer>> buildGraphGroups(int[] group,
List<List<Integer>> beforeItems,
int[] counts,
int m,
int n){
List<List<Integer>> graph = new ArrayList<List<Integer>>(m);
for(int i = 0; i < m; i++){
graph.add(new ArrayList<Integer>());
}
for(int i = 0; i < n; i++){
int toGroup = group[i];
List<Integer> fromItems = beforeItems.get(i);
for(int fromItem : fromItems){
int fromGroup = group[fromItem];
if(fromGroup != toGroup){
graph.get(fromGroup).add(toGroup);
++counts[toGroup];
}
}
}
return graph;
}
}
复杂度分析
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<>();
}
组与组的依赖关系,组抽象成点,依赖关系抽象成边,看是否有拓扑
有部位未理解,以后改
/*
* @lc app=leetcode.cn id=1203 lang=javascript
*
* [1203] 项目管理
*/
// @lc code=start
/**
* @param {number} n
* @param {number} m
* @param {number[]} group
* @param {number[][]} beforeItems
* @return {number[]}
*/
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
};
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 : []
}
// @lc code=end
空间复杂度:O(n+m)
时间复杂度:O(n+m)
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 int[] sortItems(int n, int m, int[] group, List<List<Integer>> beforeItems) {
Map<Integer,List<Integer>> group_projects = new HashMap<>();
Map<Integer,Integer> groupDegres = new HashMap<>();
Map<Integer,List<Integer>> groupNext = new HashMap<>();
Map<Integer,Integer> projectDegree = new HashMap<>();
Map<Integer,List<Integer>> projectNext = new HashMap<>();
int nonGroupIdx = m;
for(int i=0;i<n;i++){
if(group[i] == -1){
//给没有组的元素设置group
group_projects.put(nonGroupIdx,Collections.singletonList(i));
group[i] = nonGroupIdx;
nonGroupIdx++;
}else {
fillMapList(group_projects, group[i], i);
}
}
//创建图
for(int project=0;project<n;project++){
List<Integer> preList = beforeItems.get(project);
for(int pre : preList){
int preGroup = group[pre];
int projectGroup = group[project];
if(preGroup!=projectGroup){
addMapValue(groupDegres, projectGroup);
fillMapList(groupNext, preGroup, projectGroup);
}else {
addMapValue(projectDegree, project);
fillMapList(projectNext, pre, project);
}
}
}
//获取结果
List<Integer> gIdxList = new ArrayList<>();
for(int i=0;i<nonGroupIdx;i++){
gIdxList.add(i);
}
List<Integer> sortedGroup = topSort(gIdxList,groupDegres,groupNext);
if(sortedGroup.size()!=nonGroupIdx)return new int[0];
int[] ans = new int[n];
int idx = 0;
for(int sgroup : sortedGroup){
List<Integer> projectList = group_projects.get(sgroup);
if(projectList == null)continue;
List<Integer> sortedProjectList = topSort(projectList,projectDegree,projectNext);
if(sortedProjectList.size()!=projectList.size())return new int[0];
for(int project : sortedProjectList){
ans[idx++] = project;
}
}
return ans;
}
List<Integer> topSort(List<Integer> valueList, Map<Integer,Integer> degrees,Map<Integer,List<Integer>> next){
LinkedList<Integer> queue = new LinkedList<>();
for(int v : valueList){
if(degrees.get(v) == null){
queue.offerLast(v);
}
}
List<Integer> ans = new ArrayList<>();
while(!queue.isEmpty()){
int group = queue.pollFirst();
ans.add(group);
List<Integer> nextList = next.get(group);
if(nextList != null){
for(int nextRet : nextList){
int latest = decMapValue(degrees, nextRet);
if(latest == 0){
queue.offerLast(nextRet);
}
}
}
}
return ans;
}
void addMapValue(Map<Integer,Integer> map, int key){
Integer v = map.get(key);
if(v == null){
map.put(key,1);
}else {
map.put(key,v + 1);
}
}
int decMapValue(Map<Integer,Integer> map, int key){
Integer v = map.get(key);
if(v != null){
map.put(key,v - 1);
}
return v - 1;
}
void fillMapList(Map<Integer,List<Integer>> map, int key,int value){
List<Integer> v = map.get(key);
if(v == null){
v = new ArrayList<>();
map.put(key,v);
}
v.add(value);
}
}
时间和空间都是O(m+n^2)
class Solution:
# Return the topological sorted result of items
def topological_sort(self, items, indegree, adjacency_list):
q = collections.deque()
res = []
for i in items:
if indegree[i] == 0:
q.append(i)
while(q):
i = q.popleft()
res.append(i)
for adj in adjacency_list[i]:
indegree[adj] -= 1
if indegree[adj] == 0:
q.append(adj)
return res
def sortItems(self, n: int, m: int, group: List[int], beforeItems: List[List[int]]) -> List[int]:
item_indegree = collections.defaultdict(int)
group_indegree = collections.defaultdict(int)
item_adjacencies = collections.defaultdict(list)
group_adjacencies = collections.defaultdict(list)
group_items = collections.defaultdict(list)
# dummy groups for unassigned items
max_group = m
for i in range(n):
if group[i] == -1:
group[i] = max_group
max_group += 1
# Build adjacency lists for groups and items
for i in range(n):
group_items[group[i]].append(i)
for pre in beforeItems[i]:
if group[pre] == group[i]:
item_indegree[i] += 1
item_adjacencies[pre].append(i)
else:
group_indegree[group[i]] += 1
group_adjacencies[group[pre]].append(group[i])
# Topological sort for groups
sorted_groups = self.topological_sort([i for i in range(max_group)], group_indegree, group_adjacencies)
if len(sorted_groups) != max_group:
return []
res = []
for g in sorted_groups:
# Topological sort for items in each group
sorted_items = self.topological_sort(group_items[g], item_indegree, item_adjacencies)
if len(sorted_items) != len(group_items[g]):
return []
res += sorted_items
return res
Time complexity: O(V + E) V is the number of vertices in and E is the number of edges.
Space complexity: O(V + E)
var sortItems = function(n, m, group, beforeItems) {
for (let i = 0; i < group.length; i++) {
if (group[i] === -1) {
group[i] = m;
m++;
}
}
let groupAdj = new Array(m).fill(0).map(() => []);
let itemAdj = new Array(n).fill(0).map(() => []);
let groupsIndegree = new Array(m).fill(0);
let itemsIndegree = new Array(n).fill(0);
let len = group.length;
for (let i = 0; i < len; i++) {
let currentGroup = group[i];
for (let beforeItem of beforeItems[i]) {
let beforeGroup = group[beforeItem];
if (beforeGroup !== currentGroup) {
groupAdj[beforeGroup].push(currentGroup);
groupsIndegree[currentGroup]++;
}
}
}
for (let i = 0; i < n; i++) {
for (let item of beforeItems[i]) {
itemAdj[item].push(i);
itemsIndegree[i]++;
}
}
let groupList = topologicalSort(groupAdj, groupsIndegree, m);
if (groupList.length === 0) {
return [];
}
let itemList = topologicalSort(itemAdj, itemsIndegree, n);
if (itemList.length === 0) {
return [];
}
let map = new Map();
for (let item of itemList) {
let groupId = group[item];
if (!map.has(groupId)) {
map.set(groupId, []);
}
map.get(groupId).push(item);
}
let ans = [];
for (let g of groupList) {
let items = map.get(g);
if (items !== undefined) {
ans.push(...items);
}
}
return ans;
};
var topologicalSort = function (adj, inDegree, n) {
let queue = [];
let res = [];
for (let i = 0; i < inDegree.length; i++) {
if (inDegree[i] === 0) {
queue.push(i);
}
}
while (queue.length !== 0) {
let node = queue.shift();
res.push(node);
for (let successor of adj[node]) {
inDegree[successor]--;
if (inDegree[successor] === 0) {
queue.push(successor);
}
}
}
return res.length === n ? res : [];
}
problem name
https://leetcode-cn.com/problems/sort-items-by-groups-respecting-dependencies/
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:
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) {
// 第 1 步:数据预处理,给没有归属于一个组的项目编上组号
for (int i = 0; i < group.length; i++) {
if (group[i] == -1) {
group[i] = m;
m++;
}
}
// 第 2 步:实例化组和项目的邻接表
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<>();
}
// 第 3 步:建图和统计入度数组
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]++;
}
}
// 第 4 步:得到组和项目的拓扑排序结果
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);
}
// 第 6 步:把组的拓扑排序结果替换成为项目的拓扑排序结果
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<>();
}
}
(mark)
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 : [];
};
1203. 项目管理
入选理由
暂无
题目地址
https://leetcode-cn.com/problems/sort-items-by-groups-respecting-dependencies/
前置知识
- 图论
- 拓扑排序
- BFS & DFS
题目描述
公司共有 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] 不含重复元素
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) {
// 第 1 步:数据预处理,给没有归属于一个组的项目编上组号
for (int i = 0; i < group.length; i++) {
if (group[i] == -1) {
group[i] = m;
m++;
}
}
// 第 2 步:实例化组和项目的邻接表
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<>();
}
// 第 3 步:建图和统计入度数组
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]++;
}
}
// 第 4 步:得到组和项目的拓扑排序结果
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);
}
// 第 6 步:把组的拓扑排序结果替换成为项目的拓扑排序结果
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 {
vector<int> tpSort(vector<int>& nodes, unordered_map<int,unordered_set<int>> next, vector<int> inDegree) {
vector<int> res;
queue<int> q;
for (auto& n : nodes) {
if (inDegree[n] == 0)
q.push(n);
}
while (!q.empty()) {
int cur = q.front();
q.pop();
for (auto& v : next[cur]) {
--inDegree[v];
if (inDegree[v] == 0)
q.push(v);
}
}
if (res.size() == nodes.size())
return res;
return {};
}
vector<int> sortItems(int n, int m, vector<int>& group, vector<vector<int>>& beforeItems) {
vector<int> res;
unordered_map<int,unordered_set<int>> groupItems;
int nextGroupId = m;
for (int i = 0; i < n; ++i) {
if (group[i] == -1) {
group[i] = nextGroupId;
nextGroupId += 1;
}
}
unordered_map<int,unordered_set<int>> next;
unordered_map<int, int> inDegree;
for (int i = 0; i < n; ++i) {
for (auto& j : beforeItems[i]) {
if (group[i] != group[j])
continue;
if (next[j].count(i) == 0) {
next[j].insert(i);
++inDegree[i];
}
}
}
unordered_map<int, vector<int>> groupItemsOrdered;
for (auto& x : groupItems) {
int groupId = x.first;
groupItemsOrdered[groupId] = tpSort(groupItems[groupId], next, inDegree);
if (groupItemsOrdered[groupId].size() != groupItems[groupId].size())
return {};
}
next.clear();
inDegree.clear();
for (int i = 0; i < n; ++i) {
for (int j : beforeItems[i]) {
if (group[i] == group[j])
continue;
if (next[group[j]].count(group[i]) == 0) {
next[group[j]].insert(group[i]);
++inDegree[group[i]];
}
}
}
unordered_set<int> groups;
for (int i = 0; i < n; ++i) {
groups.insert(group[i]);
}
vector<int> groupOrdered = tpSort(groups, next, inDegree);
for (int groupId : groupOrdered) {
for (auto node : groupItemsOrdered(groupId)) {
res.push_back(node);
}
}
return res;
}
};
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] 不含重复元素