463. Island Perimeter - Explanation

Problem Link

Description

You are given a row x col grid representing a map where grid[i][j] = 1 represents land and grid[i][j] = 0 represents water.

Grid cells are connected horizontally/vertically (not diagonally). The grid is completely surrounded by water, and there is exactly one island (i.e., one or more connected land cells).

The island doesn't have "lakes", meaning the water inside isn't connected to the water around the island. One cell is a square with side length 1.

Return the perimeter of the island.

Example 1:

Input: grid = [
    [1,1,0,0],
    [1,0,0,0],
    [1,1,1,0],
    [0,0,1,1]
]

Output: 18

Explanation: The perimeter is the 18 red stripes shown in the image above.

Example 2:

Input: grid = [[1,0]]

Output: 4

Constraints:

  • row == grid.length
  • col == grid[i].length
  • 1 <= row, col <= 100
  • grid[i][j] is 0 or 1.
  • There is exactly one island in grid.


Topics

Company Tags

Please upgrade to NeetCode Pro to view company tags.



Prerequisites

Before attempting this problem, you should be comfortable with:

  • 2D Array (Grid) Traversal - Iterating through rows and columns of a matrix
  • Depth First Search (DFS) - Recursive exploration of connected components in a grid
  • Breadth First Search (BFS) - Level-by-level traversal using a queue

Intuition

The perimeter of an island comes from the edges of land cells that touch either water or the grid boundary. Using DFS, we can traverse all connected land cells starting from any land cell. Each time we step outside the grid or hit water, we've found one edge of the perimeter. By recursively exploring in all four directions and counting these boundary crossings, we accumulate the total perimeter.

Algorithm

  1. Traverse the grid to find the first land cell.
  2. Start dfs from that cell, marking cells as visited.
  3. For each cell in the dfs:
    • If out of bounds or water, return 1 (found a perimeter edge).
    • If already visited, return 0.
    • Otherwise, mark as visited and recursively call dfs on all four neighbors.
  4. Sum up the returned values to get the total perimeter.
class Solution:
    def islandPerimeter(self, grid: List[List[int]]) -> int:
        rows, cols = len(grid), len(grid[0])
        visit = set()

        def dfs(i, j):
            if i < 0 or j < 0 or i >= rows or j >= cols or grid[i][j] == 0:
                return 1
            if (i, j) in visit:
                return 0

            visit.add((i, j))
            perim = dfs(i, j + 1) + dfs(i + 1, j) + dfs(i, j - 1) + dfs(i - 1, j)
            return perim

        for i in range(rows):
            for j in range(cols):
                if grid[i][j]:
                    return dfs(i, j)
        return 0

Time & Space Complexity

  • Time complexity: O(mn)O(m * n)
  • Space complexity: O(mn)O(m * n)

Where mm is the number of rows and nn is the number of columns in the grid.


Intuition

BFS offers a level-by-level traversal of the island. Starting from any land cell, we explore its neighbors using a queue. The key observation remains the same: each neighbor that is water or out of bounds contributes one unit to the perimeter. By processing each land cell once and checking its four directions, we count all perimeter edges.

Algorithm

  1. Find the first land cell and initialize a queue with it.
  2. Use a visited set to avoid reprocessing cells.
  3. While the queue is not empty:
    • Dequeue a cell and check all four neighbors.
    • If a neighbor is out of bounds or water, increment the perimeter.
    • If a neighbor is unvisited land, mark it visited and enqueue it.
  4. Return the accumulated perimeter.
class Solution:
    def islandPerimeter(self, grid: List[List[int]]) -> int:
        rows, cols = len(grid), len(grid[0])
        visited = set()
        directions = [(0, 1), (1, 0), (0, -1), (-1, 0)]

        def bfs(r, c):
            queue = deque([(r, c)])
            visited.add((r, c))
            perimeter = 0

            while queue:
                x, y = queue.popleft()
                for dx, dy in directions:
                    nx, ny = x + dx, y + dy
                    if (nx < 0 or ny < 0 or nx >= rows or
                        ny >= cols or grid[nx][ny] == 0
                    ):
                        perimeter += 1
                    elif (nx, ny) not in visited:
                        visited.add((nx, ny))
                        queue.append((nx, ny))
            return perimeter

        for i in range(rows):
            for j in range(cols):
                if grid[i][j] == 1:
                    return bfs(i, j)
        return 0

Time & Space Complexity

  • Time complexity: O(mn)O(m * n)
  • Space complexity: O(mn)O(m * n)

Where mm is the number of rows and nn is the number of columns in the grid.


3. Iteration - I

Intuition

Instead of graph traversal, we can directly iterate through every cell. For each land cell, we check all four directions. If a neighbor is water or out of bounds, that direction contributes to the perimeter. This approach processes each cell independently, making it straightforward and efficient.

Algorithm

  1. Initialize a perimeter counter to 0.
  2. Iterate through every cell in the grid.
  3. For each land cell, check all four directions:
    • Add 1 to the perimeter if the neighbor is out of bounds or water.
  4. Return the total perimeter.
class Solution:
    def islandPerimeter(self, grid: List[List[int]]) -> int:
        m, n, res = len(grid), len(grid[0]), 0
        for i in range(m):
            for j in range(n):
                if grid[i][j] == 1:
                    res += (i + 1 >= m or grid[i + 1][j] == 0)
                    res += (j + 1 >= n or grid[i][j + 1] == 0)
                    res += (i - 1 < 0 or grid[i - 1][j] == 0)
                    res += (j - 1 < 0 or grid[i][j - 1] == 0)
        return res

Time & Space Complexity

  • Time complexity: O(mn)O(m * n)
  • Space complexity: O(1)O(1) extra space.

Where mm is the number of rows and nn is the number of columns in the grid.


4. Iteration - II

Intuition

Every land cell contributes 4 to the perimeter initially. However, when two land cells are adjacent, they share an edge, and both cells lose one perimeter unit on that shared side. So for each adjacent pair, we subtract 2 from the total. By only checking the top and left neighbors while iterating, we count each adjacency exactly once.

Algorithm

  1. Initialize perimeter to 0.
  2. Iterate through every cell in the grid.
  3. For each land cell:
    • Add 4 to the perimeter.
    • If the cell above is also land, subtract 2.
    • If the cell to the left is also land, subtract 2.
  4. Return the total perimeter.
class Solution:
    def islandPerimeter(self, grid: List[List[int]]) -> int:
        m, n = len(grid), len(grid[0])
        res = 0
        for r in range(m):
            for c in range(n):
                if grid[r][c] == 1:
                    res += 4
                    if r and grid[r - 1][c]:
                        res -= 2
                    if c and grid[r][c - 1] == 1:
                        res -= 2
        return res

Time & Space Complexity

  • Time complexity: O(mn)O(m * n)
  • Space complexity: O(1)O(1) extra space.

Where mm is the number of rows and nn is the number of columns in the grid.


Common Pitfalls

Double Counting Shared Edges

When two adjacent land cells share an edge, that edge should not contribute to the perimeter. A common mistake is to count all 4 sides for every land cell without subtracting the shared edges. Each adjacency between two land cells removes 2 from the total perimeter (1 from each cell).

Forgetting Boundary Conditions

Edges at the grid boundary always contribute to the perimeter. When checking neighbors, failing to properly handle out-of-bounds indices can cause missed perimeter edges or array index errors. Always verify that neighbor coordinates are within valid grid bounds before accessing them.