DDSA Solutions

1559. Detect Cycles in 2D Grid

Time: O(m*n)
Space: O(m*n)
Advertisement

Intuition

Treat cells with the same character as an undirected graph where each cell connects to up/down/left/right neighbors of equal value. A cycle exists if during DFS/BFS we reach an already-visited node that is not the parent we came from. Parent tracking is essential because the immediate back-edge to parent should not be counted as a cycle.

Algorithm

  1. 1Create a visited matrix of size m x n initialized to false.
  2. 2Iterate through every cell (i, j). If unvisited, start DFS from it with parent = (-1, -1).
  3. 3In DFS, mark current cell visited and scan 4-direction neighbors.
  4. 4Skip neighbors that are out of bounds or have different character.
  5. 5Skip the parent neighbor (the cell we came from).
  6. 6If a valid same-character neighbor is already visited and is not parent, return true (cycle found).
  7. 7Otherwise recurse into unvisited same-character neighbors. If any recursive call returns true, propagate true.
  8. 8If all components finish with no such back-edge, return false.

Example Walkthrough

Input: grid = [[a,a,a,a],[a,b,b,a],[a,b,b,a],[a,a,a,a]]

  1. 1.Start DFS from (0,0) = a and walk through connected a-cells on the border.
  2. 2.While exploring, eventually reach a neighbor that is already visited and not the direct parent.
  3. 3.This confirms a closed loop in the a-component.
  4. 4.Return true immediately.

Output: true

Common Pitfalls

  • Without parent coordinates, every undirected edge looks like a false cycle when you step back one cell.
  • Only same-character neighbors belong to the same graph component; different letters must be ignored.
  • Use iterative DFS/BFS if recursion depth is a concern on very large grids.
1559.cs
C#
public class Solution
{
    // Approach: DFS on same-character components with parent tracking; revisiting a
    // previously seen non-parent neighbor implies a cycle.
    // Time: O(m*n) Space: O(m*n)
    private static readonly int[][] DIRS = new int[][] {
        new int[] {0, 1},
        new int[] {1, 0},
        new int[] {0, -1},
        new int[] {-1, 0}
    };

    public bool ContainsCycle(char[][] grid)
    {
        int m = grid.Length;
        int n = grid[0].Length;
        bool[][] seen = new bool[m][];
        for (int i = 0; i < m; i++)
            seen[i] = new bool[n];

        for (int i = 0; i < m; ++i)
        {
            for (int j = 0; j < n; ++j)
            {
                if (seen[i][j])
                    continue;
                if (Dfs(grid, i, j, -1, -1, grid[i][j], seen))
                    return true;
            }
        }

        return false;
    }

    private bool Dfs(char[][] grid, int i, int j, int prevI, int prevJ, char c, bool[][] seen)
    {
        seen[i][j] = true;

        foreach (var dir in DIRS)
        {
            int x = i + dir[0];
            int y = j + dir[1];
            if (x < 0 || x == grid.Length || y < 0 || y == grid[0].Length)
                continue;
            if (x == prevI && y == prevJ)
                continue;
            if (grid[x][y] != c)
                continue;
            if (seen[x][y])
                return true;
            if (Dfs(grid, x, y, i, j, c, seen))
                return true;
        }

        return false;
    }
}
Advertisement
Was this solution helpful?