class StronglyConnectedComponentsComputeUtils {

	static Set<Set<Integer>> computeStronglyConnectedComponents(final int numVertex, final List<List<Integer>> outEdges) {
		final Set<Set<Integer>> stronglyConnectedComponents = new HashSet<>();

		// a vertex will be added into this stack when it is visited for the first time
		final Deque<Integer> visitingStack = new ArrayDeque<>(numVertex);
		final boolean[] onVisitingStack = new boolean[numVertex];

		// stores the order that a vertex is visited for the first time, -1 indicates it is not visited yet
		final int[] vertexIndices = new int[numVertex];
		Arrays.fill(vertexIndices, -1);

		final AtomicInteger indexCounter = new AtomicInteger(0);

		final int[] vertexLowLinks = new int[numVertex];

		for (int vertex = 0; vertex < numVertex; vertex++) {
			if (!isVisited(vertex, vertexIndices)) {
				dfs(vertex, outEdges, vertexIndices, vertexLowLinks, visitingStack, onVisitingStack, indexCounter, stronglyConnectedComponents);
			}
		}

		return stronglyConnectedComponents;
	}

	private  StronglyConnectedComponentsComputeUtils();

}