1 Cycle Detection in Graphs

Somewhere in 2015, I encountered a nice algorithmic question during an interview for an algotreading company. The question was how one can decide if there is a cycle in an undirected connected graph? There are two immediate answers here, the first is running Breadth First Search (BFS) on arbitrary node and memorizing the nodes that were already visited. The search ends either when the algorithm complete scanning the whole graph or when it reaches some node twice, outputting “No” or “Yes” respectively. Another possible solution is by running Depth First Search (DFS) and keeping a variable to count the length of the longest path explored. The algorithm declare a cycle if at any point in time the length of the path reaches the number of vertices in the graph. For the rest of this post, denote that number by .
Those two solutions are simple, and more important for this discussion, have the same space complexity. That is, both consume around the same amount of working memory (in bits) ignoring the memory needed for the input and output of the algorithm. Even though DFS have implementation that requires less memory than BFS, ultimately both requires bits. One can (informally) justify the aforementioned space complexity as follow: both algorithms have to keep track of their search (a queue in BFS and a stack is DFS) which potentially can be as large as the entire graph thus , and each node need bits for encoding so the total space complexity is bits.
During the rest of this post we will focus on space complexity rather than time complexity. We will present an algorithm that can determine if there is a cycle in bits [base on this paper] and then discuss the importance of related problem: the s-t connectivity.

2 The s-t Connectivity Problem

2.1 Solving s-t connectivity as a Sub-step

We will start from solving a slightly different problem then uses its solution as a procedure in our cycle-detection algorithm.
Introducing the undirected s-t connectivity problem: The input is an undirected graph of size and two vertices . The output should be if there is path in that connects and , and otherwise. The directed s-t connectivity is about the same but the input graph is directed (i.e its edges has directions) and the output should be whether there is a directed path from to .
Before we present the algorithm, we first define the following predicate: for any and define if exists a path from to of at most steps (i.e. edges), otherwise .
The next observations are key points needed to solve the s-t connectivity efficiently (both for directed and undirected case).
  1. For any and any , we have that if and only if such that and
  2. Let , they are connected if and only if
From here the algorithm is straightforward: denote the algorithm by that upon receiving from the graph and :
  1. If , it outputs , and if it outputs
  2. For each : if and then output
  3. Output
The solution for s-t connectivity can be achieved by outputting “Yes” if and only if .
Obviously, the depth of the recursion is and in each level of the recursion the algorithm only needs to keep track of and , which is bits, therefore the total memory complexity of the algorithm is bits.

2.2 Extending the algorithm to detect cycles

How solving the s-t connectivity problem helps us with cycles detection? The next observation answer that: let be the graph in question and two endpoints of some edge, they must stay connected after removing that edge from if and only if both participating in a cycle contained in .
For the directed case the algorithm is as follow: iterate over any edge , delete it temporarily from and check if on the resulting graph, that is, if is still connected to even after you delete the edge from to . If then declare a cycle, else, restore back the edge and continue to the next one. Note that this solution also works for undirected graphs. The memory complexity is and we done.

2.3 Is it the best we can do?

Actually, for undirected graphs there is an algorithm with bits, improving the square on the log in the construction from previous section. The curious reader can read more about it here. For the directed case it is an open question whether we can improve the or not.

2.4 Beyond Cycles in Graphs

The directed s-t connectivity problem is an important theoretical problem because it captures the “hardness” of any problem that requires logarithmic amount of memory space. The reduction to show that is actually very easy, suppose we have an algorithm that solves some problem in space where is logarithmic in (and is the size of the input), generate the following directed graph: create a vertex for any state (memory configuration) of the algorithm. Since its memory is , there are at most states (thus vertices). Create an edge from to iff is a valid possible successor state of . Add a vertex and connects to it all the states that leads to outputting “Yes”. Denote by the starting-state of the algorithm and now solving the original problem is equivalent to finding a directed path from to in the states-graph.
This reduction was presented by Walter Savitch in 1970, and it also works for Nondeterministic algorithms. The conclusion is that any nondeterministic problem that can be solved in space (where is logarithmic in the size of the input) can be solved deterministically in . Combining that conclusion with the algorithm for directed s-t connectivity yields that any problem with nondeterministic space complexity can be solved deterministically (via reduction to directed s-t connectivity) with space complexity.