题目地址:
https://leetcode.com/problems/all-ancestors-of-a-node-in-a-directed-acyclic-graph/
给定一个含 n n n个点的有向无环图,每个点编号为 0 , 1 , . . . , n − 1 0,1,...,n-1 0,1,...,n−1。对于每个点,求出其所有祖先节点(祖先节点指的是能走到这个点的所有点,不包含其本身),并且要按照点的编号从小到大排序。
可以用BFS版本的拓扑排序。设点 k k k的祖先节点集合为 f ( k ) f(k) f(k),那么对于任意点 v v v,有 f ( v ) = u ∪ ⋃ u → v f ( u ) f(v)=u\cup \bigcup_{u\to v} f(u) f(v)=u∪⋃u→vf(u)。求并集操作可以用BitSet来做,即用or函数。由拓扑排序的性质,在点 v v v入队的时候, v v v的前驱都已经遍历过,从而 v v v的前驱的 f f f值都已经并入 f ( v ) f(v) f(v)。最后对每个顶点 v v v,把 f ( v ) f(v) f(v)具体哪些位置为 1 1 1了求出来即可。代码如下:
import java.util.*;
public class Solution {
int[] h, e, ne;
int idx;
void add(int a, int b) {
e[idx] = b;
ne[idx] = h[a];
h[a] = idx++;
}
public List<List<Integer>> getAncestors(int n, int[][] edges) {
h = new int[n];
Arrays.fill(h, -1);
int m = edges.length;
e = new int[m];
ne = new int[m];
int[] ind = new int[n];
for (int[] edge : edges) {
int a = edge[0], b = edge[1];
add(a, b);
// 统计入度
ind[b]++;
}
BitSet[] bitSets = new BitSet[n];
Queue<Integer> q = new LinkedList<>();
for (int i = 0; i < n; i++) {
bitSets[i] = new BitSet();
if (ind[i] == 0) {
q.offer(i);
}
}
while (!q.isEmpty()) {
int cur = q.poll();
for (int i = h[cur]; i != -1; i = ne[i]) {
int ne = e[i];
ind[ne]--;
BitSet set = bitSets[ne];
set.or(bitSets[cur]);
set.set(cur);
if (ind[ne] == 0) {
q.offer(ne);
}
}
}
List<List<Integer>> res = new ArrayList<>();
for (int i = 0; i < n; i++) {
res.add(new ArrayList<>());
BitSet set = bitSets[i];
int idx = 0;
while (set.nextSetBit(idx) != -1) {
res.get(i).add(set.nextSetBit(idx));
idx = set.nextSetBit(idx) + 1;
}
}
return res;
}
}
时间复杂度 O ( ( n + m ) n ) O((n+m)n) O((n+m)n)( m m m是图的边数,BitSet的or需要 O ( n ) O(n) O(n)),空间 O ( n 2 ) O(n^2) O(n2)。