http://www.lintcode.com/en/problem/topological-sorting/
题目:将图中节点进行拓扑排序(假设图中至少存在一个拓扑序列)
class DirectedGraphNode {
int label;
ArrayList<DirectedGraphNode> neighbors;
DirectedGraphNode(int x) { label = x; neighbors = new ArrayList<DirectedGraphNode>(); }
};
(DirectedGraphNode类中的neighbor元素表示该节点指向的节点,即出度)
解答:主要分为三步:
1、统计所有节点的入度(indegree);
2、将所有入度为0的点放入队列中;
3、BFS(根据pop出的点,重新计算节点入度,将入度为0的点加入队列中)
代码:
public ArrayList<DirectedGraphNode> topSort(ArrayList<DirectedGraphNode> graph) {
// write your code here
if (graph == null) {
return graph;
}
ArrayList<DirectedGraphNode> res = new ArrayList<>();
Map<DirectedGraphNode, Integer> map = new HashMap<>();
for (DirectedGraphNode node : graph) {
for (DirectedGraphNode neighbor : node.neighbors) {
if (map.containsKey(neighbor)) {
map.put(neighbor, map.get(neighbor) + 1);
} else {
map.put(neighbor, 1);
}
}
}
Queue<DirectedGraphNode> queue = new LinkedList<>();
for (DirectedGraphNode node : graph) {
if (!map.containsKey(node)) {
queue.offer(node);
res.add(node);
}
}
while (!queue.isEmpty()) {
DirectedGraphNode head = queue.poll();
for (DirectedGraphNode neighbor : head.neighbors) {
map.put(neighbor, map.get(neighbor) - 1);
if (map.get(neighbor) == 0) {
queue.offer(neighbor);
res.add(neighbor);
}
}
}
return res;
}
变题一:Course Schedule
https://leetcode.com/problems/course-schedule/description/
题目:总共需要修n门课程(0 - n-1),有些课需要有先修课程,如[0, 1]表示上课程1必须先上课程0。输入总共需要修的课程总数和先修课程组合,判断能否修完全部课程;
解答:方法同上(拓扑排序三步法)
改进:无需加入list再得到最后list的长度,直接技术即可;
代码:
public boolean canFinish(int numCourses, int[][] prerequisites) {
Map<Integer, Integer> map = new HashMap<>();
Queue<Integer> queue = new LinkedList<>();
int counter = 0;
if (prerequisites == null && prerequisites.length == 0) return true;
//put courses that have prerequisites and their num of indegrees into map
for (int i = 0; i < prerequisites.length; i++) {
if (map.containsKey(prerequisites[i][0])) {
map.put(prerequisites[i][0], map.get(prerequisites[i][0]) + 1);
} else {
map.put(prerequisites[i][0], 1);
}
}
//put courses whose indegree is zero into the queue
for (int i = 0; i < numCourses; i++) {
if (!map.containsKey(i)) {
queue.offer(i);
}
}
//pop current node in queue and recalculate the indegree relates to it
while (!queue.isEmpty()) {
int node = queue.poll();
counter++;
for (int i = 0; i < prerequisites.length; i++) {
if (node == prerequisites[i][1]) {
if (map.get(prerequisites[i][0]) == 1) {
queue.offer(prerequisites[i][0]);
} else {
map.put(prerequisites[i][0], map.get(prerequisites[i][0]) - 1);
}
}
}
}
if (counter == numCourses) return true;
else return false;
}
变题二:Course ScheduleII
https://leetcode.com/problems/course-schedule-ii/description/
题目:同上,输出修全部课程的先后顺序;
解答:同上,输出结果更改即可;
变题三:Sequence Reconstruction
https://leetcode.com/problems/sequence-reconstruction/description/
题目:输入org序列、seqs序列集合,判断org是否是seqs集合中所有序列的最短父序列;
解答:1、设置两个HashMap: HashMap1<元素,指向的下个元素>, HashMap2<元素,自由度>;
2、填充两个HashMap,遇到org中不存在的元素直接返回false;遍历seqs中元素时用count3计数,若count3比org长度小,说明org肯定不是最短父序列,所以返回false;
3、遍历HashMap2, 将自由度为0的点放入队列(为保证唯一性,每次遍历只有一个自由度为0的点),将该点指向的所有下个元素自由度减1。
第一次犯错:未考虑seqs最短父序列不为1的情况。通过控制每次遍历自由度为0的数只有一个来避免;
第二次犯错:未考虑seqs存在org没有的元素。若出现org没有的元素,直接返回false;
第三次犯错:未考虑seqs为空的情况。统计seq中所有元素个数,若小于org长度则返回false;
第四次犯错:与第一次犯错相似,未考虑一开始队列存在多个自由度为0的元素;
第五次犯错:与第二次犯错相似,因为循环从第二个数开始,为考虑第一个数是否存在于org之中。在循环前面增加判断条件,需注意seq.get(0)需要在seq.size() > 0的情况下才可以进行。
代码:
public boolean sequenceReconstruction(int[] org, List<List<Integer>> seqs) {
Map<Integer, Set<Integer>> map = new HashMap<>();
Map<Integer, Integer> indegree = new HashMap<>();
int count = 0;
int count3 = 0;
for (int i = 0; i < org.length; i++) {
map.put(org[i], new HashSet<>());
indegree.put(org[i], 0);
}
for (List<Integer> seq : seqs) {
count3 += seq.size();
if (seq.size() > 0 && !map.containsKey(seq.get(0))) {
return false;
}
for (int i = 1; i < seq.size(); i++) {
int temp = seq.get(i);
if (!map.containsKey(temp)) {
return false;
}
if (map.get(seq.get(i - 1)).add(temp)) {
indegree.put(temp, indegree.get(temp) + 1);
}
}
}
if (count3 < org.length) {
return false;
}
Queue<Integer> queue = new LinkedList<>();
int count4 = 0;
for (int i = 0; i < org.length; i++) {
if (indegree.get(org[i]) == 0) {
count4++;
queue.offer(org[i]);
if (org[count++] != org[i]) {
return false;
}
}
}
if (count4 > 1) {
return false;
}
while (!queue.isEmpty()) {
int head = queue.poll();
int count2 = 0;
for (int n : map.get(head)) {
indegree.put(n, indegree.get(n) - 1);
if (indegree.get(n) == 0) {
count2++;
queue.offer(n);
if (org[count++] != n) {
return false;
}
}
}
if (count2 > 1) {
return false;
}
}
if (count != org.length) {
return false;
}
return true;
}