docs: public static boolean hasCycle(Graph<?> graph) {
      int numEdges = graph.edges().size();
      if (numEdges == 0) {
        return false; // An edge-free graph is acyclic by definition.
      }
      if (!graph.isDirected() && numEdges >= graph.nodes().size()) {
        return true; // Optimization for the undirected case: at least one cycle must exist.
      }
  
      Map<Object, NodeVisitState> visitedNodes =
          Maps.newHashMapWithExpectedSize(graph.nodes().size());
      for (Object node : graph.nodes()) {
        if (subgraphHasCycle(graph, visitedNodes, node, null)) {
          return true;
        }
      }
      return false;
    }