Loading problems...
TL;DR: To find the count of land cells that cannot reach the boundary, we perform a Depth-First Search (DFS) starting from all boundary land cells to "sink" them, then count the remaining land cells.
In the Number of Enclaves problem, we are provided with an m x n binary matrix where 0 represents sea and 1 represents land. A "move" allows travel between adjacent land cells. We need to determine the total number of land cells (1s) that are completely isolated from the grid's boundary. If a land cell is connected to the edge of the grid (either directly or through a chain of other land cells), it is not an enclave.
This is a classic grid traversal problem often seen in technical interviews, requiring efficient manipulation of connected components.
A naive approach would be to treat every land cell as a potential starting point for a path to the boundary. We could iterate through every cell in the grid. If we encounter a 1, we initiate a traversal (like BFS or DFS) to explore the entire connected island.
During this traversal, we would track a boolean flag indicating if we have touched the boundary. If the traversal finishes and the flag remains false, we add the size of that island to our total count.
Pseudo-code:
textcount = 0 visited = set() for r in 0 to m: for c in 0 to n: if grid[r][c] == 1 and (r,c) not in visited: island_size, touched_boundary = dfs(r, c, visited) if not touched_boundary: count += island_size return count
Why this is suboptimal: While this approach works, implementation complexity is higher because we must return two distinct pieces of information from the traversal (size and boundary status). Furthermore, if not implemented with a global visited set, we might re-traverse the same large island multiple times, leading to redundant computations. The primary inefficiency here is conceptual: we are checking "is this island closed?" for every island, rather than simply eliminating the open ones.
The most efficient way to solve LeetCode 1020 is to invert the problem statement. Instead of searching for enclaves directly, we should identify all land cells that are not enclaves.
By definition, a non-enclave land cell is one that can reach the boundary. This implies that any 1 located on the boundary of the grid, and any 1 connected to those boundary cells, is effectively "safe" (able to walk off the grid).
Therefore, the algorithm simplifies to:
1, we trigger a DFS to visit all connected land cells.0 to signify they are sea/processed). This effectively "sinks" the land connected to the boundary.1s remaining in the grid are guaranteed to be enclaves because they had no path to the edge.Visual Description:
Imagine the recursion tree starting at a boundary cell at (0, 0). The function calls itself for the neighbor (0, 1), adding a frame to the stack. From (0, 1), it might branch to (1, 1). The execution flow dives deep into the connected component, marking cells along the path. As the recursion hits dead ends (water or grid limits), the stack unwinds, ensuring every cell in that specific landmass is processed before the initial call returns.

m (rows) and n (cols).j from 0 to n-1.
grid[0][j] and grid[m-1][j]. If either is 1, invoke dfs().i from 0 to m-1.
grid[i][0] and grid[i][n-1]. If either is 1, invoke dfs().(r, c).r < 0, c < 0, r >= m, c >= n, or grid[r][c] == 0, return.grid[r][c] = 0.dfs(r+1, c), dfs(r-1, c), dfs(r, c+1), dfs(r, c-1).enclaves = 0.
i from 0 to m-1 and j from 0 to n-1.grid[i][j] == 1, increment enclaves.enclaves.The correctness relies on the property of connectivity. The set of all land cells can be partitioned into two subsets: (those with a path to the boundary) and (those without).
Our algorithm initiates DFS exclusively from cells physically on the boundary. Because DFS explores the entire connected component, every cell in will be visited and turned to 0.
Since the DFS never starts from an internal isolated cell, and internal cells are not reachable from boundary cells (by definition of being an enclave), all cells in remain 1.
Counting the remaining 1s therefore yields exactly .
cppclass Solution { public: int numEnclaves(vector<vector<int>>& grid) { int m = grid.size(); int n = grid[0].size(); // Helper DFS function to mark connected lands as visited (0) function<void(int, int)> dfs = [&](int r, int c) { if (r < 0 || r >= m || c < 0 || c >= n || grid[r][c] == 0) { return; } grid[r][c] = 0; // Mark as visited/sea // Visit 4 directions dfs(r + 1, c); dfs(r - 1, c); dfs(r, c + 1); dfs(r, c - 1); }; // 1. Traverse boundaries and sink connected lands for (int i = 0; i < m; ++i) { if (grid[i][0] == 1) dfs(i, 0); if (grid[i][n - 1] == 1) dfs(i, n - 1); } for (int j = 0; j < n; ++j) { if (grid[0][j] == 1) dfs(0, j); if (grid[m - 1][j] == 1) dfs(m - 1, j); } // 2. Count remaining land cells (enclaves) int enclaves = 0; for (int i = 0; i < m; ++i) { for (int j = 0; j < n; ++j) { if (grid[i][j] == 1) { enclaves++; } } } return enclaves; } };
javaclass Solution { private int m; private int n; public int numEnclaves(int[][] grid) { m = grid.length; n = grid[0].length; // 1. Traverse boundaries and sink connected lands for (int i = 0; i < m; i++) { if (grid[i][0] == 1) dfs(grid, i, 0); if (grid[i][n - 1] == 1) dfs(grid, i, n - 1); } for (int j = 0; j < n; j++) { if (grid[0][j] == 1) dfs(grid, 0, j); if (grid[m - 1][j] == 1) dfs(grid, m - 1, j); } // 2. Count remaining land cells (enclaves) int enclaves = 0; for (int i = 0; i < m; i++) { for (int j = 0; j < n; j++) { if (grid[i][j] == 1) { enclaves++; } } } return enclaves; } private void dfs(int[][] grid, int r, int c) { // Boundary checks and sea check if (r < 0 || r >= m || c < 0 || c >= n || grid[r][c] == 0) { return; } // Mark as visited by turning land to sea grid[r][c] = 0; // Recurse in 4 directions dfs(grid, r + 1, c); dfs(grid, r - 1, c); dfs(grid, r, c + 1); dfs(grid, r, c - 1); } }
pythonimport sys # Increase recursion depth for large grids sys.setrecursionlimit(10000) class Solution: def numEnclaves(self, grid: List[List[int]]) -> int: m, n = len(grid), len(grid[0]) def dfs(r, c): # Base case: out of bounds or water if r < 0 or r >= m or c < 0 or c >= n or grid[r][c] == 0: return # Mark as visited (sink the island) grid[r][c] = 0 # Visit neighbors dfs(r + 1, c) dfs(r - 1, c) dfs(r, c + 1) dfs(r, c - 1) # 1. Traverse boundaries and sink connected lands for i in range(m): if grid[i][0] == 1: dfs(i, 0) if grid[i][n - 1] == 1: dfs(i, n - 1) for j in range(n): if grid[0][j] == 1: dfs(0, j) if grid[m - 1][j] == 1: dfs(m - 1, j) # 2. Count remaining land cells (enclaves) enclaves = 0 for i in range(m): for j in range(n): if grid[i][j] == 1: enclaves += 1 return enclaves
0. The final count requires iterating over the entire grid once, which is . The dominant term is .The Graph DFS - Connected Components pattern used in LeetCode 1020 is highly versatile. Here is how it applies to similar problems:
Why does my solution result in a RecursionError in Python?
sys.setrecursionlimit or an iterative stack-based DFS.Why is my answer slightly off (too high)?
Why do I get a Time Limit Exceeded (TLE)?
Can I count enclaves during the first DFS pass?