Open azl397985856 opened 3 years ago
做两次拓扑排序
实现语言: C++
class Solution {
public:
vector<int> sortItems(int n, int m, vector<int>& group, vector<vector<int>>& beforeItems) {
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;
}
groupItems[group[i]].insert(i);
}
// 分别为两个组建图
unordered_map<int, unordered_set<int>> next;
unordered_map<int, int> inDegree;
for (int i = 0; i < n; i++)
for (int j : beforeItems[i])
{
if (group[i] != group[j])
continue;
if (next[j].count(i) == 0)
{
next[j].insert(i);
inDegree[i] += 1;
}
}
// 分别得到两个组内的拓扑排序结果
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]] += 1;
}
}
// 对两个组进行拓扑排序
unordered_set<int> groups;
for (int i = 0; i < n; i++)
groups.insert(group[i]);
vector<int> groupOrdered = tpSort(groups, next, inDegree);
vector<int> res;
for (int groupId : groupOrdered)
{
for (auto node : groupItemsOrdered[groupId])
res.push_back(node);
}
return res;
}
vector<int> tpSort(unordered_set<int>& nodes, unordered_map<int, unordered_set<int>>& next, unordered_map<int, int>& inDegree)
{
queue<int> q;
vector<int> res;
for (auto node : nodes)
{
if (inDegree[node] == 0)
q.push(node);
}
while (!q.empty())
{
int cur = q.front();
q.pop();
res.push_back(cur);
for (auto next : next[cur])
{
inDegree[next] -= 1;
if (inDegree[next] == 0)
q.push(next);
}
}
if (res.size() == nodes.size())
return res;
return {};
}
};
def sortItems(n, m, group, beforeItems):
# set each -1 as a new group with group_id gi
gi = max(group)
for i in range(n):
if group[i] < 0:
gi += 1
group[i] = gi
# topo sort elements in "nodes"
def topo(src, dst, nodes):
q = [i for i in nodes if not src[i]]
for x in q:
for y in dst[x]:
src[y].remove(x)
if not src[y]:
q.append(y)
return q if len(q) == len(nodes) else None
# build DAG on group ids
nodes = set(group)
src, dst = {i: set() for i in nodes}, collections.defaultdict(set)
for d in range(n):
for s in beforeItems[d]:
gd, gs = group[d], group[s]
if gd != gs:
src[gd].add(gs)
dst[gs].add(gd)
# topo sort group id
group_order = topo(src, dst, nodes)
if not group_order:
return []
# elements in each group
g2i = collections.defaultdict(list)
for i in range(n):
g2i[group[i]].append(i)
order = []
for gid in group_order:
# build DAG on elements in group[gid]
nodes = g2i[gid]
src, dst = {i: set() for i in nodes}, collections.defaultdict(set)
for d in nodes:
for s in beforeItems[d]:
if s in nodes:
src[d].add(s)
dst[s].add(d)
# topo sort elements in group[gid]
in_group_order = topo(src, dst, nodes)
if not in_group_order:
return []
order += in_group_order
return order
抄袭打卡先
思路:
代码 实现语言: C++
class Solution {
public:
vector<int> sortItems(int n, int m, vector<int>& group, vector<vector<int>>& beforeItems) {
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;
}
groupItems[group[i]].insert(i);
}
// 分别为两个组建图
unordered_map<int, unordered_set<int>> next;
unordered_map<int, int> inDegree;
for (int i = 0; i < n; i++)
for (int j : beforeItems[i])
{
if (group[i] != group[j])
continue;
if (next[j].count(i) == 0)
{
next[j].insert(i);
inDegree[i] += 1;
}
}
// 分别得到两个组内的拓扑排序结果
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]] += 1;
}
}
// 对两个组进行拓扑排序
unordered_set<int> groups;
for (int i = 0; i < n; i++)
groups.insert(group[i]);
vector<int> groupOrdered = tpSort(groups, next, inDegree);
vector<int> res;
for (int groupId : groupOrdered)
{
for (auto node : groupItemsOrdered[groupId])
res.push_back(node);
}
return res;
}
vector<int> tpSort(unordered_set<int>& nodes, unordered_map<int, unordered_set<int>>& next, unordered_map<int, int>& inDegree)
{
queue<int> q;
vector<int> res;
for (auto node : nodes)
{
if (inDegree[node] == 0)
q.push(node);
}
while (!q.empty())
{
int cur = q.front();
q.pop();
res.push_back(cur);
for (auto next : next[cur])
{
inDegree[next] -= 1;
if (inDegree[next] == 0)
q.push(next);
}
}
if (res.size() == nodes.size())
return res;
return {};
}
};
复杂度分析: 时间复杂度:O(m + n^2),这里 n 是项目的总数,m 是组的总数 空间复杂度:O(m + n^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;
}
}
这一题目不是很熟,主要参考了解答。
拓扑排序是靠DFS,首先找到indegree为0的node,然后将其相邻节点的indegree-1,并将其加入queue
在为什么要进行两次排序的时候思考了很久,想清楚了。因为我们把任务分配给组的时候,引入了组的依赖关系。所以我们需要先排序有依赖关系的组,然后在组内排序项目的依赖。
其实我这里有疑问,这里可能会引入循环依赖。
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, beforeItems):
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 beforeItem in beforeItems[project]:
if group[beforeItem] != group[project]:
group_indegree[group[project]] += 1
group_neighbors[group[beforeItem]].append(group[project])
else:
project_indegree[project] += 1
project_neighbors[beforeItem].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(V+E)
空间复杂度:O(V+E)
C++ Code:
class Solution {
public:
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>> graphGroup(m);
vector<int> inorderGroup(m,0);
vector<vector<int>> graphItem(n);
vector<int> inorderItem(n,0);
for(int i=0; i<group.size(); i++)
{
for(int j =0; j < beforeItems[i].size(); j++)
{
if(group[beforeItems[i][j]] != group[i])
{
// graphGroup[group[i]].push_back(group[beforeItems[i][j]]);
graphGroup[group[beforeItems[i][j]]].push_back(group[i]);
inorderGroup[group[i]]++;
// inorderGroup[group[beforeItems[i][j]]]++;
}
//graphItem[i].push_back(beforeItems[i][j]);
//inorderItem[beforeItems[i][j]]++;
graphItem[beforeItems[i][j]].push_back(i);
inorderItem[i]++;
}
}
vector<int> groupOrder= topoOrder(graphGroup, inorderGroup);
if(groupOrder.size()==0)
return vector<int>();
vector<int> itemOrder = topoOrder(graphItem, inorderItem);
if(itemOrder.size()==0)
return vector<int>();
vector<vector<int>> groupSort(m);
for(int i=0; i< itemOrder.size(); i++)
{
groupSort[group[itemOrder[i]]].push_back(itemOrder[i]);
}
vector<int> ret;
for(int i=0; i< groupOrder.size(); i++)
{
for(int j=0; j< groupSort[groupOrder[i]].size(); j++)
{
ret.push_back(groupSort[groupOrder[i]][j]);
}
}
return ret;
}
vector<int> topoOrder(vector<vector<int>>& graph, vector<int>& inorder)
{
int node = graph.size();
queue<int> que;
for(int i=0; i< node; i++)
{
if(inorder[i]==0)
{
que.push(i);
}
}
vector<int> res;
while(que.size())
{
int isize =que.size();
for(int i=0; i< que.size(); i++)
{
int topNode = que.front();
que.pop();
res.push_back(topNode);
for(int j=0; j < graph[topNode].size(); j++)
{
int nextNode =graph[topNode][j];
inorder[nextNode]--;
if(inorder[nextNode]==0)
{
que.push(nextNode);
}
}
}
}
for(int i=0; i< node; i++)
{
if(inorder[i]!=0)
return vector<int>();
}
return res;
}
};
没写完 占个坑有空了再来补全吧
class Solution:
def sortItems(self, n: int, m: int, group: List[int], beforeItems: List[List[int]]) -> List[int]:
graph = defaultdict(list)
ggraph = defaultdict(list)
indgr = defaultdict(int)
gindgr = defaultdict(int)
gps = defaultdict(set)
for i in range(n):
gps[group[i]].add(i)
'''TODO:
for unassigned task, assign a unique group id.
build group dependency graph, if toposort toget an group order
if group order is not toposortable, return []
topsort the tasks for each group. get a project order
finally, using the group order, output the project of each group.
'''
for i in range(n):
for p in beforeItems[i]:
graph[p].append(i)
indgr[i] += 1
queue = deque()
for i in range(n):
if indgr[i] == 0:
queue.append(i)
ret = []
while queue:
node = queue.popleft()
ret.append([group[node],node])
for i in graph[node]:
indgr[i] -= 1
if indgr[i] == 0:
queue.append(i)
if len(ret) == n:
return ret
return []
···
class Solution {
public int[] sortItems(int n, int m, int[] group, List<List<Integer>> beforeItems) {
//不属于任何组的任务指派个独立组id
for (int i = 0; i < n; i++) {
if (group[i] == -1) {
group[i] = m;
m++;
}
}
List<Set<Integer>> groupRsList = new ArrayList<>();
List<List<Integer>> groupItems = new ArrayList<>();
for (int i = 0; i < m; i++) {
groupItems.add(new ArrayList<>());
groupRsList.add(new LinkedHashSet<>());
}
for (int i = 0; i < n; i++) {
groupItems.get(group[i]).add(i);
}
//下一个组
List<Set<Integer>> groupNextList = new ArrayList<>();
for (int i = 0; i < m; i++) {
groupNextList.add(new HashSet<>());
}
//下一个任务
List<Set<Integer>> itemNextList = new ArrayList<>();
for (int i = 0; i < n; i++) {
itemNextList.add(new HashSet<>());
}
//任务入度
int[] itemIn = new int[n];
for (int i = 0; i < beforeItems.size(); i++) {
List<Integer> beforeItem = beforeItems.get(i);
itemIn[i] = beforeItem.size();
for (Integer item : beforeItem) {
itemNextList.get(item).add(i);
}
}
Queue<Integer> queue = new LinkedList<>();
int handleItemCount=0;
for (int i = 0; i < n; i++) {
if (itemIn[i] == 0) {
queue.add(i);
handleItemCount++;
}
}
//组入度
int[] groupIn = new int[m];
Set<Integer> nextQueue = new HashSet<>();
while (!queue.isEmpty()) {
int item = queue.poll();
groupRsList.get(group[item]).add(item);
Set<Integer> nextList = itemNextList.get(item);
for (Integer nextItem : nextList) {
itemIn[nextItem]--;
if (itemIn[nextItem] < 0) {
return new int[0];
}
if (group[nextItem] != group[item]) {
if(!groupNextList.get(group[item]).contains(group[nextItem])){
groupNextList.get(group[item]).add(group[nextItem]);
groupIn[group[nextItem]]++;
}
}
if (itemIn[nextItem] == 0) {
handleItemCount++;
nextQueue.add(nextItem);
}
}
if (queue.isEmpty()) {
queue.addAll(nextQueue);
nextQueue.clear();
}
}
if(handleItemCount<n){
return new int[0];
}
int handleGroupCount=0;
List<Integer> itemRsList = new ArrayList<>();
List<Integer> rsList = new ArrayList<>();
for (int i = 0; i < m; i++) {
if(groupIn[i]==0){
handleGroupCount++;
rsList.add(i);
itemRsList.addAll(groupRsList.get(i));
queue.add(i);
}
}
while (!queue.isEmpty()){
int groupId=queue.poll();
Set<Integer> nextList=groupNextList.get(groupId);
for(Integer nextGroupId:nextList){
groupIn[nextGroupId]--;
if(groupIn[nextGroupId]<0){
return new int[0];
}
if(groupIn[nextGroupId]==0){
handleGroupCount++;
nextQueue.add(nextGroupId);
rsList.add(nextGroupId);
itemRsList.addAll(groupRsList.get(nextGroupId));
}
}
if (queue.isEmpty()) {
queue.addAll(nextQueue);
nextQueue.clear();
}
}
if(handleGroupCount<m){
return new int[0];
}
int[] rs = new int[n];
for (int i = 0; i < itemRsList.size(); i++) {
rs[i]=itemRsList.get(i);
}
return rs;
}
}
复杂度分析
令 n 为数组长度。
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;
}
}
class Solution:
def sortItems(self, n: int, m: int, group: List[int], beforeItems: List[List[int]]) -> List[int]:
# DAG
def topological(items, indegree, neighbors):
q = collections.deque([])
res = []
for i in items:
if not indegree[i]:
q.append(i)
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
max_gid = m
for project in range(n):
if group[project] == -1:
group[project] = 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]:
# group graph
if group[before] != group[project]:
group_indegree[group[project]] += 1
group_neighbors[group[before]].append(group[project])
# project graph
else:
project_indegree[project] += 1
project_neighbors[before].append(project)
ans = []
group_queue = topological([i for i in range(max_gid)], group_indegree, group_neighbors)
if len(group_queue) != max_gid:
return []
for gid in group_queue:
project_queue = topological(group_projects[gid], project_indegree, project_neighbors)
if len(project_queue) != len(group_projects[gid]):
return []
ans += project_queue
return ans
拓扑排序 BFS Python 3 Code
class Soution:
def sortItems(self, n, m, group, beforeItems):
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 []
# STEP 1: Create a new group for each item that belongs to no group.
for u in range(len(group)):
if group[u] == -1:
group[u] = m
m+=1
# STEP 2: Build directed graphs for items and groups.
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
# STEP 3: Find topological orders of items and groups.
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 []
# STEP 4: Find order of items within each group.
order_within_group = collections.defaultdict(list)
for v in item_order:
order_within_group[group[v]].append(v)
# STEP 5. Combine ordered groups.
res = []
for group in group_order:
res += order_within_group[group]
return res
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];
}
// 根据项目的拓扑排序结果,项目到组的多对一关系,建立组到项目的一对多关系
// 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<>();
}
}
参考的官方题解 因为我们要group 同一个group的project在一起 所以我们要建立group的dep
所以先建group 和 project 的graph,再拓扑排序 group first ,然后对于每个group内部的project 再进行一个拓扑排序
from collections import deque, defaultdict
def topological_sort(node_list, in_degree_dict, graph):
result = []
queue = deque()
for node in node_list:
if in_degree_dict[node] == 0:
queue.append(node)
while queue:
node = queue.pop()
result.append(node)
for next_node in graph[node]:
in_degree_dict[next_node] -= 1
if in_degree_dict[next_node] == 0:
queue.appendleft(next_node)
return result
class Solution:
def sortItems(
self, n: int, m: int, group: List[int], beforeItems: List[List[int]]
) -> List[int]:
# assign unique group id for project without a group
max_project = m
for i in range(len(group)):
if group[i] == -1:
group[i] = max_project
max_project += 1
distinct_group_list = list(set(group))
# build group and project graph
group_in_degree = defaultdict(int)
group_graph = defaultdict(list)
project_in_degree = defaultdict(int)
project_graph = defaultdict(list)
group_project_dict = defaultdict(list)
for i in range(len(beforeItems)):
group_project_dict[group[i]].append(i)
for dep in beforeItems[i]:
if group[i] != group[dep]:
group_in_degree[group[i]] += 1
group_graph[group[dep]].append(group[i])
else:
project_in_degree[i] += 1
project_graph[dep].append(i)
# sort the group first
sorted_group = topological_sort(
distinct_group_list, group_in_degree, group_graph
)
if len(sorted_group) != len(distinct_group_list):
return []
result = []
# sort project in each group
for i in sorted_group:
sorted_projects = topological_sort(
group_project_dict[i], project_in_degree, project_graph
)
if len(sorted_projects) != len(group_project_dict[i]):
return []
result.extend(sorted_projects)
return result
m 是图里面边的个数, n是图里面node 的个数
时间 O(m+n)
空间 O(m+n)
https://leetcode.com/problems/sort-items-by-groups-respecting-dependencies/
这题我连题目都没看懂。我再回头来看。 >_<
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 : [];
};
Topological sorting. Topologically sort items and groups. Assign sorted item to its corresponding group. Based on the group order to append it's items. For each project without group, assign it to a new different group.
import collections
class Solution:
def sortItems(self, n, m, group, beforeItems):
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 = self.get_top_order(graph_items, indegree_items)
group_order = self.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
def get_top_order(self, 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 []
Time: O(V+E) Space: O(V+E)
拓扑排序。
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;
}
};
不会做 抄的标答
class Solution:
def sortItems(self, n: int, m: int, group: List[int], beforeItems: List[List[int]]) -> List[int]:
max_id = m
for i in range(n):
if group[i] == -1:
group[i] = max_id
max_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 i in range(n):
group_projects[group[i]].append(i)
for pre in beforeItems[i]:
if group[pre] != group[i]:
group_indegree[group[i]] += 1
group_neighbors[group[pre]].append(group[i])
else:
project_indegree[i]+=1
project_neighbors[pre].append(i)
res = []
group_queue = self.tp_sort([i for i in range(max_id)], group_indegree, group_neighbors)
if len(group_queue) != max_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
def tp_sort(self, items, indegree, neighbors):
res = []
queue = collections.deque([])
for item in items:
if indegree[item] == 0:
queue.append(item)
while(queue):
t = queue.popleft()
res.append(t)
for neighbor in neighbors[t]:
indegree[neighbor] -= 1
if indegree[neighbor] == 0:
queue.append(neighbor)
return res
Space: O(V+E) Time: O(V+E)
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
时间复杂度:O(V+E) 空间复杂度:O(V+E)
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;
// 给未分配的 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;
}
};
Time:O(n) Space:O(n)
func sortItems(n int, m int, group []int, beforeItems [][]int) []int {
groups, inDegrees := make([][]int, n+m), make([]int, n+m)
for i, g := range group {
if g > -1 {
g += n
groups[g] = append(groups[g], i)
inDegrees[i]++
}
}
for i, ancestors := range beforeItems {
gi := group[i]
if gi == -1 {
gi = i
} else {
gi += n
}
for _, ancestor := range ancestors {
ga := group[ancestor]
if ga == -1 {
ga = ancestor
} else {
ga += n
}
if gi == ga {
groups[ancestor] = append(groups[ancestor], i)
inDegrees[i]++
} else {
groups[ga] = append(groups[ga], gi)
inDegrees[gi]++
}
}
}
res := []int{}
for i, d := range inDegrees {
if d == 0 {
sortItemsDFS(i, n, &res, &inDegrees, &groups)
}
}
if len(res) != n {
return nil
}
return res
}
func sortItemsDFS(i, n int, res, inDegrees *[]int, groups *[][]int) {
if i < n {
*res = append(*res, i)
}
(*inDegrees)[i] = -1
for _, ch := range (*groups)[i] {
if (*inDegrees)[ch]--; (*inDegrees)[ch] == 0 {
sortItemsDFS(ch, n, res, inDegrees, groups)
}
}
}
···
title: "Day 31 1203. 项目管理" date: 2021-10-10T10:30:34+08:00 tags: ["Leetcode", "c++", "graph"] categories: ["91-day-algorithm"] draft: true
有 n 个项目,每个项目或者不属于任何小组,或者属于 m 个小组之一。group[i] 表示第 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] 不含重复元素
- 1、拓扑排序类问题,今日问题较难,使用单拓扑排序可能不太行,所以尝试使用双拓扑排序的思路!由于这几天生病,只能CV一下,过几天后再来补一道解析!
class Solution {
public:
vector<int> sortItems(int n, int m, vector<int>& group, vector<vector<int>>& beforeItems) {
vector<int> ans, blank;
//如果某个项目不属于当前任何小组,新建一个小组,并且把它分给这个小组,为了避免冲突,新的小组编号从m开始
for(int i = 0; i < group.size(); i++)
if(group[i] == -1)
{
group[i] = m++;
}
//分别保存组间依赖关系、项目之间的依赖关系、各个小组负责的项目
vector<int> topoGroup[m], topoItem[n], groupItem[m];
//分别保存小组和项目在图中的入度
int groupDgr[m], itemDgr[n];
//避免添加多余的有向边,依赖关系只需要一条有向边就可以表示
unordered_set<int> vis;
memset(groupDgr, 0, sizeof groupDgr);
memset(itemDgr, 0 ,sizeof itemDgr);
for(int i = 0; i < beforeItems.size(); i++)
{
//将项目添加到对应的组内
groupItem[group[i]].push_back(i);
for(int j = 0; j < beforeItems[i].size(); j++)
{
//hashval用于判断是否有重复的邮箱边出现
int u = beforeItems[i][j], hashval = group[u] * m + group[i];
topoItem[u].push_back(i);
itemDgr[i]++;
//自己不能依赖自己
if(group[i] == group[u] || vis.find(hashval) != vis.end()) continue;
vis.insert(hashval);
topoGroup[group[u]].push_back(group[i]);
groupDgr[group[i]]++;
}
}
//groupOrder保存了组的顺序
vector<int> groupOrder;
queue<int> q;
for(int i = 0; i < m; i++)
if(groupDgr[i] == 0) q.push(i);
while(!q.empty())
{
int u = q.front();
q.pop();
groupOrder.push_back(u);
for(int i = 0; i < topoGroup[u].size(); i++)
{
int v = topoGroup[u][i];
groupDgr[v]--;
if(groupDgr[v] == 0) q.push(v);
}
}
//判断组内项目是否满足拓扑排序
for(int i = 0; i < groupOrder.size(); i++)
{
int t = groupOrder[i];
for(int j = 0; j < groupItem[t].size(); j++)
{
int u = groupItem[t][j];
if(itemDgr[u] == 0) q.push(u);
}
int cnt = 0;
while(!q.empty())
{
int u = q.front();
q.pop();
cnt++;
ans.push_back(u);
for(int j = 0; j < topoItem[u].size(); j++)
{
int v = topoItem[u][j];
itemDgr[v]--;
if(itemDgr[v] == 0 && group[v] == t) q.push(v);
}
}
if(cnt != groupItem[t].size()) return blank;
}
//如果组间关系不能满足拓扑排序,必定有项目不能加入ans内
if(ans.size() != n) return blank;
return ans;
}
};
时间复杂度:O(n + m)
空间复杂度:O(n + m)
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;
}
}
Time: O(M+N) Space: O(M+N)
class Solution {
public:
vector
vector
//分别保存组间依赖关系、项目之间的依赖关系、各个小组负责的项目
vector<int> topoGroup[m], topoItem[n], groupItem[m];
//分别保存小组和项目在图中的入度
int groupDgr[m], itemDgr[n];
//避免添加多余的有向边,依赖关系只需要一条有向边就可以表示
unordered_set<int> vis;
memset(groupDgr, 0, sizeof groupDgr);
memset(itemDgr, 0 ,sizeof itemDgr);
for(int i = 0; i < beforeItems.size(); i++)
{
//将项目添加到对应的组内
groupItem[group[i]].push_back(i);
for(int j = 0; j < beforeItems[i].size(); j++)
{
//hashval用于判断是否有重复的邮箱边出现
int u = beforeItems[i][j], hashval = group[u] * m + group[i];
topoItem[u].push_back(i);
itemDgr[i]++;
//自己不能依赖自己
if(group[i] == group[u] || vis.find(hashval) != vis.end()) continue;
vis.insert(hashval);
topoGroup[group[u]].push_back(group[i]);
groupDgr[group[i]]++;
}
}
//groupOrder保存了组的顺序
vector<int> groupOrder;
queue<int> q;
for(int i = 0; i < m; i++)
if(groupDgr[i] == 0) q.push(i);
while(!q.empty())
{
int u = q.front();
q.pop();
groupOrder.push_back(u);
for(int i = 0; i < topoGroup[u].size(); i++)
{
int v = topoGroup[u][i];
groupDgr[v]--;
if(groupDgr[v] == 0) q.push(v);
}
}
//判断组内项目是否满足拓扑排序
for(int i = 0; i < groupOrder.size(); i++)
{
int t = groupOrder[i];
for(int j = 0; j < groupItem[t].size(); j++)
{
int u = groupItem[t][j];
if(itemDgr[u] == 0) q.push(u);
}
int cnt = 0;
while(!q.empty())
{
int u = q.front();
q.pop();
cnt++;
ans.push_back(u);
for(int j = 0; j < topoItem[u].size(); j++)
{
int v = topoItem[u][j];
itemDgr[v]--;
if(itemDgr[v] == 0 && group[v] == t) q.push(v);
}
}
if(cnt != groupItem[t].size()) return blank;
}
//如果组间关系不能满足拓扑排序,必定有项目不能加入ans内
if(ans.size() != n) return blank;
return ans;
}
};
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;
}
};
class Solution:
def has_cycle(self, graph, cur_node, visited, result):
if visited[cur_node] == 1:
return False
if visited[cur_node] == 2:
return True
visited[cur_node] = 2
for next_node in graph[cur_node]:
if self.has_cycle(graph, next_node, visited, result):
return True
visited[cur_node] = 1
result.append(cur_node)
return False
def sortItems(self, n: int, m: int, group: List[int],
beforeItems: List[List[int]]) -> List[int]:
# Map between group_id and item_ids
group_items_map = defaultdict(list)
# Visited for items in each group. Will be used later
visited_item = defaultdict(dict)
for i in range(n):
# Assign no-group items to a new group
if group[i] == -1:
group[i] = m
m += 1
group_items_map[group[i]].append(i)
visited_item[group[i]][i] = 0
# key - group_id : value - next_groups
graph_group = defaultdict(set)
# key - group_id : value - {key - item_id : value: next_items}
graph_item = {i: defaultdict(list) for i in range(m)}
# Create graph for items and groups
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 two items belong to different groups,
# add a dependency between groups
# Otherwise, add a dependency between items in the same group
if group_before != group_after:
graph_group[group_before].add(group_after)
else:
graph_item[group_before][item_before].append(item_after)
# Use DFS to find group order
visited_group = [0] * m
group_order = []
for group_id in range(m):
if self.has_cycle(graph_group, group_id,
visited_group, group_order):
return []
# Use DFS to find item order in each group
full_item_order = []
for group_id in group_order:
for item_id in group_items_map[group_id]:
if self.has_cycle(graph_item[group_id], item_id,
visited_item[group_id], full_item_order):
return []
return full_item_order[::-1]
完全不懂,抄的答案。晚点慢慢再仔细分析。
fun sortItems(n: Int, m: Int, group: IntArray, beforeItems: List<List<Int>>): IntArray {
var ng = m
val groups = group.mapIndexed { i, g -> if (g == -1) ng++ else g }
val igraph = Array<MutableSet<Int>>(n) { mutableSetOf() }
val ggraph = Array<MutableSet<Int>>(ng) { mutableSetOf() }
for (i in 0 until n) {
for (b in beforeItems[i]) {
val ig = groups[i]
val bg = groups[b]
if (ig == bg) {
igraph[b].add(i)
} else {
ggraph[bg].add(ig)
}
}
}
fun inDegree(graph: Array<MutableSet<Int>>): IntArray {
val res = IntArray(graph.size) { 0 }
for (es in graph) {
for (e in es) {
res[e]++
}
}
return res
}
fun topSort(graph: Array<MutableSet<Int>>): List<Int> {
val ins = inDegree(graph)
val queue = mutableListOf<Int>()
for ((i, d) in ins.withIndex()) {
if (d == 0) queue.add(i)
}
val res = mutableListOf<Int>()
while (queue.isNotEmpty()) {
val top = queue.removeAt(0)
res.add(top)
for (next in graph[top]) {
ins[next]--
if (ins[next] == 0) queue.add(next)
}
}
return res
}
val itop = topSort(igraph)
if (itop.size != igraph.size) return intArrayOf()
val tops = Array<MutableList<Int>>(ng) { mutableListOf() }
for (i in itop) {
tops[groups[i]].add(i)
}
val gtop = topSort(ggraph)
if (gtop.size != ggraph.size) return intArrayOf()
val res = mutableListOf<Int>()
for (g in gtop) {
res.addAll(tops[g])
}
return res.toIntArray()
}
这题不会,写个210凑数
class Solution {;
public int[] findOrder(int numCourses, int[][] prerequisites) {
// establish a course DAG
List<Integer>[] dag = new List[numCourses];
int[] inDegree = new int[numCourses];
for (int[] edge : prerequisites) {
// edge[1] -> edge[0]
if (dag[edge[1]] == null) {
dag[edge[1]] = new ArrayList<>();
}
dag[edge[1]].add(edge[0]);
inDegree[edge[0]] += 1;
}
// top-sort bfs
// List<Integer> ans = new ArrayList<>();
// bfs(ans, dag, inDegree);
// return ans.size() == numCourses ? ans.stream().mapToInt(Integer::intValue).toArray() : new int[0];
// top sort dfs
int[] visited = new int[numCourses]; // 0 - not visited, 1 - visiting, 2 - visited
// boolean hasCircle = false;
Deque<Integer> stack = new LinkedList<>();
for (int i=0; i<numCourses; i++) {
if (visited[i] == 0) {
if (!dfs(i, dag, visited, stack)) {
return new int[0];
}
}
}
return stack.stream().mapToInt(Integer::intValue).toArray();
}
private void bfs(List<Integer> ans, List<Integer>[] dag, int[] inDegree) {
Queue<Integer> q = new LinkedList<>();
for (int i=0; i<dag.length; i++) {
if (inDegree[i] == 0) {
q.offer(i);
}
}
while (!q.isEmpty()) {
int course = q.poll();
ans.add(course);
if (dag[course] != null) {
for (int next : dag[course]) {
inDegree[next] -= 1;
if (inDegree[next] == 0) {
q.offer(next);
}
}
}
}
}
private boolean dfs(int course, List<Integer>[] dag, int[] visited, Deque<Integer> stack) {
visited[course] = 1;
if (dag[course] != null) {
for (int next : dag[course]) {
if (visited[next] == 0) {
if (!dfs(next, dag, visited, stack)) {
return false;
}
} else if (visited[next] == 1) {
// circle
return false;
} else {
// no op for visited == 2
}
}
}
visited[course] = 2;
stack.push(course);
return true;
}
}
TC: O(v+e) SC: O(v+e)
python
class Solution:
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
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 {
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(n+m),其中 n 为点数,m 为边数
空间复杂度:O(n+m)
打卡
Topology sort. Note: that if item a is in group 1, item b is in group 2, and item a needs to happen before item b, then group 1 needs to happen before group2.
Note:
class Solution {
public:
vector<int> topologySort(set<int>& items, vector<int>& indegrees, map<int, set<int>>& relation) {
queue<int> proQ;
vector<int> ans;
for (int v : items)
if (indegrees[v] == 0) {
proQ.push(v);
}
while (!proQ.empty()) {
int i = proQ.front();
proQ.pop();
ans.push_back(i);
for (int v : relation[i]) {
if (--indegrees[v] == 0)
proQ.push(v);
}
}
return ans;
}
vector<int> sortItems(int n, int m, vector<int>& group, vector<vector<int>>& beforeItems) {
map<int, set<int>> group2item;
vector<int> itmeIndegrees(n,0);
map<int, set<int>> groupRelation;
map<int, set<int>> itemRelation;
set<int> groupIds;
vector<int> ans;
int groupIDMax = m;
for (int i = 0; i < group.size(); i++) {
if (group[i] == -1)
group[i] = groupIDMax++;
group2item[group[i]].insert(i);
groupIds.insert(group[i]);
}
vector<int> groupIndegrees(groupIDMax,0);
for (int i = 0; i < beforeItems.size(); i++) {
for (int j : beforeItems[i]) {
// In the same group, order items.
if (group[i] == group[j]) {
if (!itemRelation[j].count(i)) {
itmeIndegrees[i]++;
itemRelation[j].insert(i);
}
} else {
// In different group, order groups
if (!groupRelation[group[j]].count(group[i])) {
groupIndegrees[group[i]]++;
groupRelation[group[j]].insert(group[i]);
}
}
}
}
vector<int> groupOrder = topologySort(groupIds, groupIndegrees, groupRelation);
if (groupOrder.size() != groupIds.size())
return vector<int>();
for (int v : groupOrder) {
vector<int> tmpOrder = topologySort(group2item[v], itmeIndegrees, itemRelation);
if (tmpOrder.size() != group2item[v].size())
return vector<int>();
for (int x : tmpOrder)
ans.push_back(x);
}
return ans;
}
};
O(v + e)
O(v + e)
BFS + 拓扑排序
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;
}
};
时间 O(m+n)
空间 O(m+n)
class Solution:
def topologicalSort(self, vertices, edges):
"""
vertices: list of any type
edges: list of list of two indices of vertices
"""
n = len(vertices)
out_edges = [[] for _ in range(n)]
in_deg = [0 for _ in range(n)]
for i, j in edges:
out_edges[i].append(j)
in_deg[j] += 1
inds = [i for i in range(n) if in_deg[i] == 0]
for i in inds:
for j in out_edges[i]:
in_deg[j] -= 1
if in_deg[j] == 0:
inds.append(j)
if len(inds) == n:
return [vertices[i] for i in inds]
else:
raise RuntimeError # there is a loop
def sortItems(self, n: int, m: int, group: List[int], beforeItems: List[List[int]]) -> List[int]:
groups = [[] for _ in range(m)] # items in each group
intra_lookup = [{} for _ in range(m)] # indices of items in each group
for i in range(n):
if group[i] == -1: # create new group for items belonging to no group
intra_lookup.append({i: 0}) # one item in such group
groups.append([i])
else:
g = group[i]
intra_lookup[g][i] = len(groups[g])
groups[g].append(i)
# remove empty groups
intra_lookup = [g for i, g in enumerate(intra_lookup) if groups[i]]
groups = [g for g in groups if g]
m = len(groups)
inter_lookup = [None for _ in range(n)] # group each item belongs to
for g, ita in enumerate(intra_lookup):
for i in ita:
inter_lookup[i] = g
# beforeItems are splited into two
inter_b, intra_b = [], [[]for _ in range(m)]
for i, b in enumerate(beforeItems):
gi = inter_lookup[i]
for j in b:
gj = inter_lookup[j]
if gi == gj:
# edge inside one group
intra_b[gi].append(
[intra_lookup[gi][j], intra_lookup[gi][i]])
else:
# edge between groups
inter_b.append([gj, gi])
try:
# sort groups
groups = self.topologicalSort(list(zip(groups, intra_b)),
inter_b)
# sort items inside each group
for g in range(m):
groups[g] = self.topologicalSort(groups[g][0], groups[g][1])
return sum(groups, [])
except RuntimeError:
return []
https://leetcode-cn.com/problems/sort-items-by-groups-respecting-dependencies/
参考官网的拓扑排序
class Solution {
public int[] sortItems(int n, int m, int[] group, List<List<Integer>> beforeItems) {
Map<Integer, List<Integer>> gGraph = new HashMap<>();
Map<Integer, List<Integer>> iGraph = new HashMap<>();
for(int i = 0; i < group.length; i++) {
if(group[i] == -1) group[i] = m++;
}
int[] itemInDegree = new int[n];
int[] groupInDegree = new int[m];
for(int to = 0; to < beforeItems.size(); to++) {
int toGroup = group[to];
for(int from : beforeItems.get(to)) {
itemInDegree[to]++;
if(!iGraph.containsKey(from)) {
iGraph.put(from, new ArrayList<Integer>());
}
iGraph.get(from).add(to);
}
}
//build item graph
for(int to = 0; to < group.length; to++) {
int toGroup = group[to];
for(int from : beforeItems.get(to)) {
int fromGroup = group[from];
if(gGraph.containsKey(fromGroup)) {
gGraph.put(fromGroup, new ArrayList<Integer>());
}
if(fromGroup != toGroup) {
groupInDegree[toGroup]++;
gGraph.get(fromGroup).add(toGroup);
}
}
}
List<Integer> iList = tpSort(iGraph, itemInDegree, n);
List<Integer> gList = tpSort(gGraph, groupInDegree, m);
if(iList.size() == 0 || gList.size() == 0) return new int[0];
Map<Integer, List<Integer>> groupedList = new HashMap<>();
for(int item : iList) {
int grp = group[item];
if(!groupedList.containsKey(grp)) {
groupedList.put(grp, new ArrayList<Integer>());
}
groupedList.get(grp).add(item);
}
int i = 0;
int[] ans = new int[n];
for(int grp : gList) {
if(!groupedList.containsKey(grp)) continue;
for(int item : groupedList.get(grp)) {
ans[i] = item;
i++;
}
}
return ans;
}
public List<Integer> tpSort(Map<Integer, List<Integer>> graph, int[] inDegree, int count) {
List<Integer> ans = new ArrayList<>();
Queue<Integer> q = new LinkedList<>();
for(int i = 0; i < inDegree.length; i++) {
if(inDegree[i] == 0) q.offer(i);
}
while(!q.isEmpty()) {
int cur = q.poll();
ans.add(cur);
if(!graph.containsKey(cur)) continue;
for(int next : graph.get(cur)) {
inDegree[next]--;
if(inDegree[next] == 0) q.offer(next);
}
}
return count == ans.size() ? ans : new ArrayList<>();
}
}
O(V + E)
O(V + E)
class Solution:
def sortItems(self, n: int, m: int, group: List[int], beforeItems: List[List[int]]) -> List[int]:
def makeGraphs():
items = collections.defaultdict(dict)
groups = {}
for i, g in enumerate(group):
items[g][i] = set()
if g not in groups:
groups[g] = set()
for i, ancestors in enumerate(beforeItems):
for anc in ancestors:
if group[i] != group[anc]:
groups[group[anc]].add(group[i])
else:
items[group[i]][anc].add(i)
return items, groups
items, groups = makeGraphs()
def sortGraph(G, stack):
visiting = set()
visited = set()
def dfs(node):
if node in visiting: return False
if node in visited: return True
visiting.add(node)
visited.add(node)
for child in G[node]:
if not dfs(child):
return False
stack.append(node)
visiting.remove(node)
return True
for node in G:
if not dfs(node):
return []
return stack
groupsStack = []
sortGraph(groups, groupsStack)
if not groupsStack:
return []
res = []
for g in reversed(groupsStack):
groupItems = []
sortGraph(items[g], groupItems)
if not groupItems:
return []
res.extend(reversed(groupItems))
return res
官方题解
使用语言:Python3
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(N + E), N is number of node, E is number of edge 空间复杂度:O(N + E)
https://leetcode.com/problems/sort-items-by-groups-respecting-dependencies/
Hard
Medium
This is a topological sorting problem. Firstly sort the groups, then sort the items in each group.
class Solution:
def sortItems(self, n: int, m: int, group: List[int], beforeItems: List[List[int]]) -> List[int]:
# Helper function: returns topological order of a graph, if it exists.
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 []
# STEP 1: Create a new group for each item that belongs to no group.
for u in range(len(group)):
if group[u] == -1:
group[u] = m
m+=1
# STEP 2: Build directed graphs for items and groups.
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
# STEP 3: Find topological orders of items and groups.
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 []
# STEP 4: Find order of items within each group.
order_within_group = collections.defaultdict(list)
for v in item_order:
order_within_group[group[v]].append(v)
# STEP 5. Combine ordered groups.
res = []
for group in group_order:
res += order_within_group[group]
return res
时间复杂度: O(V+E) 空间复杂度:O(V+E)
参考了一些解法。两次拓扑排序。因为item之间的依赖关系,导致了组与组之间也有了先后顺序。
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>[] 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<>();
}
int[] groupIndegree = new int[m];
int[] itemIndegree = new int[n];
// construct adjecent graph of groups and items
for (int i = 0; i < n; i++) {
int groupId = group[i];
for (int beforeItem : beforeItems.get(i)) {
int beforeGroupId = group[beforeItem];
if (beforeGroupId != groupId) {
groupGraph[beforeGroupId].add(groupId);
groupIndegree[groupId]++;
} else {
itemGraph[beforeItem].add(i);
itemIndegree[i]++;
}
}
}
List<Integer> groupList = topSort(groupGraph, groupIndegree, m);
List<Integer> itemList = topSort(itemGraph, itemIndegree, n);
if (groupList.size() == 0 || itemList.size() == 0) {
return new int[0];
}
Map<Integer, List<Integer>> map = new HashMap<>();
for (Integer item : itemList) {
map.computeIfAbsent(group[item], key -> new ArrayList<>()).add(item);
}
List<Integer> res = new ArrayList<>();
for (Integer groupId : groupList) {
List<Integer> items = map.getOrDefault(groupId, new ArrayList<>());
res.addAll(items);
}
return res.stream().mapToInt(Integer::valueOf).toArray();
}
public List<Integer> topSort(List<Integer>[] graph, int[] indegree, int n) {
List<Integer> ret = new ArrayList<>();
Queue<Integer> q = new LinkedList<>();
for (int i = 0; i < n; i++) {
if (indegree[i] == 0) {
q.offer(i);
}
}
while (!q.isEmpty()) {
Integer u = q.poll();
ret.add(u);
for (Integer v : graph[u]) {
indegree[v]--;
if (indegree[v] == 0) {
q.offer(v);
}
}
}
return ret.size() == n ? ret : new ArrayList<>();
}
}
时间:O(v + e)
空间:O(v + e)
class Solution {
public:
vector<int> sortItems(int n, int m, vector<int>& group, vector<vector<int>>& beforeItems) {
unordered_map<int, vector<int>> groupGraph;
unordered_map<int, int> groupIndegree;
vector<vector<int>> groupItems(m, vector<int>());
for(int i = 0; i < n;i++) {
if(group[i] != -1) {
groupItems[group[i]].push_back(i);
} else {
group[i] = groupItems.size();
groupItems.push_back(vector<int>{i});
}
}
for(int j = 0; j < groupItems.size(); j++) {
groupIndegree[j] = 0;
}
for(int i = 0; i < n ;i++) {
for(const int beforeItem : beforeItems[i]) {
int groupId = group[i];
if(groupId != group[beforeItem]) {
groupGraph[group[beforeItem]].push_back(groupId);
groupIndegree[groupId]++;
}
}
}
vector<int> sortedGroup = graphSort(groupGraph, groupIndegree);
vector<int> res;
if (sortedGroup.size() < groupItems.size()) return res;
for(const int&i : sortedGroup) {
vector<int> curOrder = itemsSort(groupItems[i], beforeItems,group);
if(curOrder.size() < groupItems[i].size())
return vector<int>();
for(auto j: curOrder)
res.push_back(j);
}
return res;
}
vector<int> itemsSort(vector<int>&items , vector<vector<int>>& beforeItems, vector<int>& group) {
unordered_map<int, vector<int>> itemsGraph;
unordered_map<int, int> itemsIndegree;
for(auto item : items) {
itemsIndegree[item] = 0;
for(const int beforeItem:beforeItems[item]) {
if(group[item] == group[beforeItem]) {
itemsGraph[beforeItem].push_back(item);
itemsIndegree[item]++;
}
}
}
vector<int> res = graphSort(itemsGraph, itemsIndegree);
return res;
}
vector<int> graphSort(unordered_map<int, vector<int>> &edge, unordered_map<int, int>& indegree) {
queue<int> q;
vector<int> res;
for(auto a:indegree) {
if(a.second == 0)
q.push(a.first);
}
while(!q.empty()) {
int temp = q.front();
q.pop();
res.push_back(temp);
for(auto b : edge[temp]) {
indegree[b]--;
if(indegree[b] == 0)
q.push(b);
}
}
return res;
}
};
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) {
//不属于任何组的任务指派个独立组id
for (int i = 0; i < n; i++) {
if (group[i] == -1) {
group[i] = m;
m++;
}
}
List<Set<Integer>> groupRsList = new ArrayList<>();
List<List<Integer>> groupItems = new ArrayList<>();
for (int i = 0; i < m; i++) {
groupItems.add(new ArrayList<>());
groupRsList.add(new LinkedHashSet<>());
}
for (int i = 0; i < n; i++) {
groupItems.get(group[i]).add(i);
}
//下一个组
List<Set<Integer>> groupNextList = new ArrayList<>();
for (int i = 0; i < m; i++) {
groupNextList.add(new HashSet<>());
}
//下一个任务
List<Set<Integer>> itemNextList = new ArrayList<>();
for (int i = 0; i < n; i++) {
itemNextList.add(new HashSet<>());
}
//任务入度
int[] itemIn = new int[n];
for (int i = 0; i < beforeItems.size(); i++) {
List<Integer> beforeItem = beforeItems.get(i);
itemIn[i] = beforeItem.size();
for (Integer item : beforeItem) {
itemNextList.get(item).add(i);
}
}
Queue<Integer> queue = new LinkedList<>();
int handleItemCount=0;
for (int i = 0; i < n; i++) {
if (itemIn[i] == 0) {
queue.add(i);
handleItemCount++;
}
}
//组入度
int[] groupIn = new int[m];
Set<Integer> nextQueue = new HashSet<>();
while (!queue.isEmpty()) {
int item = queue.poll();
groupRsList.get(group[item]).add(item);
Set<Integer> nextList = itemNextList.get(item);
for (Integer nextItem : nextList) {
itemIn[nextItem]--;
if (itemIn[nextItem] < 0) {
return new int[0];
}
if (group[nextItem] != group[item]) {
if(!groupNextList.get(group[item]).contains(group[nextItem])){
groupNextList.get(group[item]).add(group[nextItem]);
groupIn[group[nextItem]]++;
}
}
if (itemIn[nextItem] == 0) {
handleItemCount++;
nextQueue.add(nextItem);
}
}
if (queue.isEmpty()) {
queue.addAll(nextQueue);
nextQueue.clear();
}
}
if(handleItemCount<n){
return new int[0];
}
int handleGroupCount=0;
List<Integer> itemRsList = new ArrayList<>();
List<Integer> rsList = new ArrayList<>();
for (int i = 0; i < m; i++) {
if(groupIn[i]==0){
handleGroupCount++;
rsList.add(i);
itemRsList.addAll(groupRsList.get(i));
queue.add(i);
}
}
while (!queue.isEmpty()){
int groupId=queue.poll();
Set<Integer> nextList=groupNextList.get(groupId);
for(Integer nextGroupId:nextList){
groupIn[nextGroupId]--;
if(groupIn[nextGroupId]<0){
return new int[0];
}
if(groupIn[nextGroupId]==0){
handleGroupCount++;
nextQueue.add(nextGroupId);
rsList.add(nextGroupId);
itemRsList.addAll(groupRsList.get(nextGroupId));
}
}
if (queue.isEmpty()) {
queue.addAll(nextQueue);
nextQueue.clear();
}
}
if(handleGroupCount<m){
return new int[0];
}
int[] rs = new int[n];
for (int i = 0; i < itemRsList.size(); i++) {
rs[i]=itemRsList.get(i);
}
return rs;
}
}
复杂度
时间复杂度:O(N)
空间复杂度:O(N)
var sortItems = function(n, m, group, beforeItems) {
const groupItems = new Array(m + n).fill(0).map(() => []);
// 将未分组自身为一组
let k = m;
for (let i = 0; i < n; i++) {
if (group[i] === -1) {
group[i] = k++;
}
groupItems[group[i]].push(i);
}
// 组间关系及入度
const groupGraph = new Array(m + n).fill(0).map(() => []);
const groupIn = new Array(m + n).fill(0);
// 组内关系及入度
const itemGraph = new Array(n).fill(0).map(() => []);
const itemIn = new Array(n).fill(0);
for (let i = 0; i < n; i++) {
const curGroupId = group[i];
for (let beforeIndex of beforeItems[i]) {
const beforeGroupId = group[beforeIndex];
if (curGroupId === beforeGroupId) {
// 组相同,加入组内元素关系及入度
itemIn[i] += 1;
itemGraph[beforeIndex].push(i);
} else {
// 如果组间关系存在,不重复保存
if (groupGraph[beforeGroupId].indexOf(curGroupId) >= 0) continue;
groupIn[curGroupId] += 1;
groupGraph[beforeGroupId].push(curGroupId);
}
}
}
/**
* @param {number[][]} graph 关联关系
* @param {number[]} inNum 入度
* @param {number[]} groupItems 组元素或同组内元素
* @return {number[]}
*/
const topSort = (graph, inNum, groupItems) => {
const queue = [];
// 入度为0的加入队列
for (let inIndex of groupItems) {
if (inNum[inIndex] === 0) {
queue.push(inIndex);
}
}
const temp = [];
while (queue.length) {
// 取队首元素
const index = queue.shift();
temp.push(index);
for (let i = 0; i < graph[index].length; i++) {
// 指向元素的下标
const inIndex = graph[index][i];
// 入度减1
inNum[inIndex] -= 1;
// 当入度为0时,也加入到队列
if (inNum[inIndex] === 0) {
queue.push(inIndex)
}
}
}
return temp.length === groupItems.length ? temp : [];
}
// 表示所有组
const groupIds = new Array(m + n).fill(0).map((item, index) => index);
const groupTopSort = topSort(groupGraph, groupIn, groupIds);
if (groupTopSort.length === 0) {
return [];
}
let res = [];
for (let groupId of groupTopSort) {
const curGroup = groupItems[groupId];
// 组内可能没有分配任务
if (curGroup.length === 0) {
continue;
}
if (curGroup.length === 1) {
// 长度为1,未分组元素,组内无需排序
res.push(curGroup[0]);
} else {
// 长度大于1,组内进行排序
const itemTopSort = topSort(itemGraph, itemIn, curGroup);
if (itemTopSort.length === 0) {
return [];
}
res = [...res, ...itemTopSort];
}
}
return res
};
Explanation
Python
class class Solution:
def sortItems(self, n: int, m: int, group: List[int], beforeItems: List[List[int]]) -> List[int]:
def topSort(deg, graph):
stack = [v for v in range(len(graph)) if deg[v] == 0]
res = []
while stack:
curr = stack.pop()
res.append(curr)
for v in graph[curr]:
deg[v] -= 1
if deg[v] == 0:
stack.append(v)
return res if len(res) == len(graph) else []
for i in range(len(group)):
if group[i] == -1:
group[i] = m
m += 1
groupGraph = [[] for _ in range(m)]
itemGraph = [[] for _ in range(n)]
groupDegree = [0] * m
itemDegree = [0] * n
for i in range(n):
for item in beforeItems[i]:
itemGraph[item].append(i)
itemDegree[i] += 1
if group[item] != group[i]:
groupDegree[group[i]] += 1
groupGraph[group[item]].append(group[i])
groupTopSort = topSort(groupDegree, groupGraph)
itemTopSort = topSort(itemDegree, itemGraph)
if not groupTopSort or not itemTopSort:
return []
orderInGroup = defaultdict(list)
for i in itemTopSort:
orderInGroup[group[i]].append(i)
ans = []
for j in groupTopSort:
ans += orderInGroup[j]
return ans
Complexity:
O(m+n)
O(m+n)
两次拓扑排序
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++;
}
}
Map<Integer, List<Integer>> groupNeighbor = new HashMap<>();
Map<Integer, List<Integer>> itemsNeighbor = new HashMap<>();
//初始化
for (int i = 0; i < m; i++) {
groupNeighbor.put(i, new ArrayList<Integer>());
}
for (int i = 0; i < n; i++) {
itemsNeighbor.put(i, new ArrayList<Integer>());
}
//构图
int[] groupIndegree = new int[m];
int[] itemsIndegree = new int[n];
for (int i = 0; i < group.length; i++) {
int curGrp = group[i];
for (int beforeItem : beforeItems.get(i)) {
int beforeGrp = group[beforeItem];
if (beforeGrp != curGrp) {
groupNeighbor.get(beforeGrp).add(curGrp);
groupIndegree[curGrp]++;
}
}
}
for (int i = 0; i < n; i++) {
for (int beforeItem : beforeItems.get(i)) {
itemsNeighbor.get(beforeItem).add(i);
itemsIndegree[i]++;
}
}
//topo sort
List<Integer> groupSort = topoSort(groupIndegree, groupNeighbor, m);
if (groupSort.size() == 0) {
return new int[0];
}
List<Integer> itemsSort = topoSort(itemsIndegree, itemsNeighbor, n);
if (itemsSort.size() == 0) {
return new int[0];
}
Map<Integer, List<Integer>> groupItemMap = new HashMap<>();
//用哈希表建立group 对应多个items的映射
for (int item : itemsSort) {
if (!groupItemMap.containsKey(group[item])) {
groupItemMap.put(group[item], new ArrayList<>());
}
groupItemMap.get(group[item]).add(item);
}
List<Integer> res = new ArrayList<>();
//根据group的topo排序依次加入group -> items的映射
for (Integer grp : groupSort) {
List<Integer> temp = groupItemMap.getOrDefault(grp, new ArrayList<>());
res.addAll(temp);
}
//list 转成 int[]
return res.stream().mapToInt(Integer::valueOf).toArray();
}
private List<Integer> topoSort(int[] indegreeCnt, Map<Integer, List<Integer>> neighbors, int n) {
List<Integer> res = new ArrayList<>();
Queue<Integer> queue = new ArrayDeque<>();
for (int i = 0; i < n; i++) {
if (indegreeCnt[i] == 0) {
queue.offer(i);
res.add(i);
}
}
while (!queue.isEmpty()) {
int cur = queue.poll();
for (int neighbor : neighbors.get(cur)) {
indegreeCnt[neighbor] = indegreeCnt[neighbor] - 1;
if (indegreeCnt[neighbor] == 0) {
queue.offer(neighbor);
res.add(neighbor);
}
}
}
if (res.size() == n) {
return res;
}
return new ArrayList<>();
}
}
https://leetcode.com/problems/sort-items-by-groups-respecting-dependencies/
class Solution {
public int[] sortItems(int n, int m, int[] group, List<List<Integer>> beforeItems) {
// preprocessing - assign new group id to the -1th groups
for(int i = 0; i < n; i++){
if(group[i] == -1){
group[i] = m;
m++;
}
}
// build the group and item adjacent lists and indegree arrays
// to make sure all the groups and items have corresponding list in the map, initiate with empty list first
Map<Integer, List<Integer>> groupAdjacentList = new HashMap<>();
for(int i = 0; i < m; i++){
groupAdjacentList.put(i, new ArrayList<>());
}
Map<Integer, List<Integer>> itemAdjacentList = new HashMap<>();
for(int i = 0; i < n; i++){
itemAdjacentList.put(i, new ArrayList<>());
}
int[] groupIndegree = new int[m];
int[] itemIndegree = new int[n];
for(int i = 0; i < n; i++){ // iterate all the items and build the adjacent list and indegree array
int currentGroup = group[i];
for(int dependentItem: beforeItems.get(i)){
// item
itemAdjacentList.get(dependentItem).add(i);
itemIndegree[i]++;
// group
int dependentGroup = group[dependentItem];
if(dependentGroup != currentGroup){ // avoid putting duplicate groups in the adjacent list
groupAdjacentList.get(dependentGroup).add(currentGroup);
groupIndegree[currentGroup]++;
}
}
}
// sort the groups and items in topo order
// if the groups or items cannot be sorted in topological order, then no solution, return empty array
List<Integer> groupTopoList = topoSort(groupAdjacentList, groupIndegree);
if(groupTopoList.size() == 0){
return new int[0];
}
List<Integer> itemTopoList = topoSort(itemAdjacentList, itemIndegree);
if(itemTopoList.size() == 0){
return new int[0];
}
// group the items in topo order as per their groups
Map<Integer, List<Integer>> groupMap = new HashMap<>();
for(int i = 0; i < n; i++){
int item = itemTopoList.get(i);
int groupId = group[item];
if(!groupMap.containsKey(groupId)){
groupMap.put(groupId, new ArrayList<>());
}
groupMap.get(groupId).add(item);
}
// As per group topo order, put the items in each group to the result array
int[] result = new int[n];
int index = 0;
for(int i = 0; i < m; i++){
int groupId = groupTopoList.get(i);
if(!groupMap.containsKey(groupId)){
continue;
}
for(int item: groupMap.get(groupId)){
result[index] = item;
index++;
}
}
return result;
}
private List<Integer> topoSort(Map<Integer, List<Integer>> adjacentList, int[] indegree){
List<Integer> result = new ArrayList<>();
Queue<Integer> queue = new LinkedList<>();
for(int i = 0; i < indegree.length; i++){
if(indegree[i] == 0){
queue.offer(i);
}
}
while(!queue.isEmpty()){
int item = queue.poll();
result.add(item);
for(int nextItem: adjacentList.get(item)){
indegree[nextItem]--;
if(indegree[nextItem] == 0){
queue.offer(nextItem);
}
}
}
// if result size doesn't equal to the number of items
// it means the items cannot be sorted in topo order
if(result.size() != indegree.length){
return new ArrayList<>();
}
return result;
}
}
Official Java Solution
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<>();
}
// 第 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]++;
}
}
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<>();
}
}
太难了,官方解也看得很吃力
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<>();
}
// 第 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]++;
}
}
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<>();
}
}
【day 31】1203. 项目管理
https://leetcode-cn.com/problems/sort-items-by-groups-respecting-dependencies/
思路:关键点:
拓扑排序:采用BFS,从入度为 0 的开始(没有任何依赖),将其邻居(依赖)逐步加入队列,并将入度(依赖数目)减去 1,如果减到 0 了,说明没啥依赖了,将其入队处理。因为入度不可能为0,不可能存在环
依赖关系 两层 1、由于项目分组,项目之间的依赖关系导致组之间也有依赖,组的依赖优先于项目 2、同一组内项目之间存在依赖关系
无人负责的项目处理:之间用新编号来给项目编号就行
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_degree = 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_degree[group[project]] += 1 #pre->project project 组入度加一
group_neighbors[group[pre]].append(group[project]) #project的组成为 pre组的邻居
else:
project_indegree[project] += 1 #依赖的项目在同一个组,project入度加一
project_neighbors[pre].append(project)##project成为 pre的邻居
ans = []
# 组的拓扑排序,先排组的拓扑序列
group_queue = self.tp_sort([i for i in range(max_group_id)], group_degree,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( V +E ) V 和 E 分别为图中的点和边的数目,每个点和边被遍历了一次,组拓扑是O(m+E1 ),项目拓扑排序是,O(n +E2 ),在入度计算时为,O(n^2 ),因此整个题的复杂度为O(n^ +m+E1+E2 ) 比较合适,n为项目数,m为组数,e为边数
空间复杂度:O(m+n^2) 组的邻接表 O(m)、项目的邻接表 O(n^2)
mark一下,今天状态不好,看不动,回头再看
type Node struct{
preCount int
NextIDs []int
}
func sortItems(n int, m int, group []int, beforeItems [][]int) []int {
groupItems := make([][]int, m+n)
maxGroupID := m-1
for i:=0;i<n;i++{
if group[i] == -1{
maxGroupID++
group[i] = maxGroupID
}
groupItems[group[i]] = append(groupItems[group[i]], i)
}
gItem := make([]Node, n)
for i:=0; i < n;i++{
for _, preID := range beforeItems[i]{
gItem[i].preCount++
gItem[preID].NextIDs = append(gItem[preID].NextIDs, i)
}
}
gGroup := make([]Node, maxGroupID+1)
for i:=0; i<n; i++{
curID := group[i]
for _,preID := range beforeItems[i]{
preID := group[preID]
if curID == preID{
continue
}
gGroup[curID].preCount++
gGroup[preID].NextIDs = append(gGroup[preID].NextIDs, curID)
}
}
q := make([]int, 0)
for i,v := range gGroup{
if v.preCount == 0{
q = append(q,i)
}
}
retGroup := make([]int, 0)
for len(q) > 0{
k := len(q)
for k>0{
k--
curID := q[0]
q = q[1:]
retGroup = append(retGroup,curID)
for _,NextID := range gGroup[curID].NextIDs{
gGroup[NextID].preCount--
if gGroup[NextID].preCount == 0{
q = append(q,NextID)
}
}
}
}
if len(retGroup) != maxGroupID+1{
return []int{}
}
ret := make([]int, 0)
for j:=0; j <= maxGroupID; j++{
q = make([]int,0)
for _,id := range groupItems[retGroup[j]]{
if gItem[id].preCount == 0{
q = append(q,id)
}
}
for len(q) > 0{
k := len(q)
for k > 0{
k--
curID := q[0]
q = q[1:]
ret = append(ret, curID)
for _,nextID := range gItem[curID].NextIDs{
gItem[nextID].preCount--
if gItem[nextID].preCount== 0 && group[nextID]==retGroup[j]{
q = append(q, nextID)
}
}
}
}
}
if len(ret) != n {
return []int{}
}
return ret
}
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] 不含重复元素