从给定的依赖项中查找任务的顺序
您必须选择总共 n 个任务,标记为从 0 到 n-1。一些任务可能有前置任务,例如选择任务 0 必须先完成任务 1,表示为一对:[0, 1]
给定任务总数和先决条件对列表,返回您应该选择完成所有任务的任务顺序。
可能有多个正确的订单,您只需退回其中一个即可。如果不可能完成所有任务,则返回一个空数组。
例子:
Input: 2, [[1, 0]]
Output: [0, 1]
Explanation: There are a total of 2 tasks to pick. To pick task 1 you should have finished task 0. So the correct task order is [0, 1] .
Input: 4, [[1, 0], [2, 0], [3, 1], [3, 2]]
Output: [0, 1, 2, 3] or [0, 2, 1, 3]
Explanation: There are a total of 4 tasks to pick. To pick task 3 you should have finished both tasks 1 and 2. Both tasks 1 and 2 should be pick after you finished task 0. So one correct task order is [0, 1, 2, 3]. Another correct ordering is [0, 2, 1, 3].
问:谷歌、推特、亚马逊和更多公司。
解:我们可以把这个问题看成一个图(与拓扑排序有关)问题。所有任务都是图的节点,如果任务 u 是任务 v 的先决条件,我们将添加从节点 u 到节点 v 的有向边。现在,这个问题相当于找到节点/任务的拓扑排序(使用拓扑排序) 在由先决条件表示的图中。如果图中存在循环,则不可能完成所有任务(因为在这种情况下,任务没有任何拓扑顺序)。 BFS和DFS都可以用拓扑排序来解决。
由于pair对于图算法的实现不方便,我们先将其转化为图。如果任务 u 是任务 v 的先决条件,我们将添加一条从节点 u 到节点 v 的有向边。
使用 BFS 进行拓扑排序
这里我们使用卡恩算法进行拓扑排序。 BFS 使用每个节点的入度。我们将首先尝试找到一个度数为 0 的节点。如果我们不这样做,则图中一定有一个循环,我们返回 false。否则我们找到了一个。我们将其入度设置为 -1 以防止再次访问它并将其所有邻居的入度减少 1。此过程将重复 n(节点数)次。
// CPP program to find order to process tasks
// so that all tasks can be finished. This program
// mainly uses Kahn's algorithm.
#include
using namespace std;
// Returns adjacency list representation of graph from
// given set of pairs.
vector > make_graph(int numTasks,
vector >& prerequisites)
{
vector > graph(numTasks);
for (auto pre : prerequisites)
graph[pre.second].insert(pre.first);
return graph;
}
// Computes in-degree of every vertex
vector compute_indegree(vector >& graph)
{
vector degrees(graph.size(), 0);
for (auto neighbors : graph)
for (int neigh : neighbors)
degrees[neigh]++;
return degrees;
}
// main function for topological sorting
vector findOrder(int numTasks,
vector >& prerequisites)
{
// Create an adjacency list
vector > graph =
make_graph(numTasks, prerequisites);
// Find vertices of zero degree
vector degrees = compute_indegree(graph);
queue zeros;
for (int i = 0; i < numTasks; i++)
if (!degrees[i])
zeros.push(i);
// Find vertices in topological order
// starting with vertices of 0 degree
// and reducing degrees of adjacent.
vector toposort;
for (int i = 0; i < numTasks; i++) {
if (zeros.empty())
return {};
int zero = zeros.front();
zeros.pop();
toposort.push_back(zero);
for (int neigh : graph[zero]) {
if (!--degrees[neigh])
zeros.push(neigh);
}
}
return toposort;
}
// Driver code
int main()
{
int numTasks = 4;
vector > prerequisites;
// for prerequisites: [[1, 0], [2, 1], [3, 2]]
prerequisites.push_back(make_pair(1, 0));
prerequisites.push_back(make_pair(2, 1));
prerequisites.push_back(make_pair(3, 2));
vector v = findOrder(numTasks, prerequisites);
for (int i = 0; i < v.size(); i++) {
cout << v[i] << " ";
}
return 0;
}
0 1 2 3
使用 DFS 进行拓扑排序:
在这个实现中,我们使用基于 DFS 的拓扑排序算法。
// CPP program to find Topological sorting using
// DFS
#include
using namespace std;
// Returns adjacency list representation of graph from
// given set of pairs.
vector > make_graph(int numTasks,
vector >& prerequisites)
{
vector > graph(numTasks);
for (auto pre : prerequisites)
graph[pre.second].insert(pre.first);
return graph;
}
// Does DFS and adds nodes to Topological Sort
bool dfs(vector >& graph, int node,
vector& onpath, vector& visited,
vector& toposort)
{
if (visited[node])
return false;
onpath[node] = visited[node] = true;
for (int neigh : graph[node])
if (onpath[neigh] || dfs(graph, neigh, onpath, visited, toposort))
return true;
toposort.push_back(node);
return onpath[node] = false;
}
// Returns an order of tasks so that all tasks can be
// finished.
vector findOrder(int numTasks, vector >& prerequisites)
{
vector > graph = make_graph(numTasks, prerequisites);
vector toposort;
vector onpath(numTasks, false), visited(numTasks, false);
for (int i = 0; i < numTasks; i++)
if (!visited[i] && dfs(graph, i, onpath, visited, toposort))
return {};
reverse(toposort.begin(), toposort.end());
return toposort;
}
int main()
{
int numTasks = 4;
vector > prerequisites;
// for prerequisites: [[1, 0], [2, 1], [3, 2]]
prerequisites.push_back(make_pair(1, 0));
prerequisites.push_back(make_pair(2, 1));
prerequisites.push_back(make_pair(3, 2));
vector v = findOrder(numTasks, prerequisites);
for (int i = 0; i < v.size(); i++) {
cout << v[i] << " ";
}
return 0;
}
0 1 2 3
参考: https://leetcode.com/problems/course-schedule-ii/