LeetCode 463 - Island Perimeter
The problem asks us to calculate the perimeter of an island represented in a 2D grid. Each cell in the grid is either land (1) or water (0). The island consists of one or more connected land cells, where connectivity is strictly horizontal or vertical.
Difficulty: 🟢 Easy
Topics: Array, Depth-First Search, Breadth-First Search, Matrix
Solution
Problem Understanding
The problem asks us to calculate the perimeter of an island represented in a 2D grid. Each cell in the grid is either land (1) or water (0). The island consists of one or more connected land cells, where connectivity is strictly horizontal or vertical. The grid is completely surrounded by water, and there are no lakes, meaning any water cell that is completely enclosed by land does not exist. The output is a single integer representing the total perimeter of the island.
The key constraints are that the grid dimensions are small (up to 100x100), the grid contains exactly one island, and each cell is either land or water. These constraints mean we can afford an O(mn) solution, where m and n are the number of rows and columns. Important edge cases include very small grids, a single land cell, or land cells on the grid boundary. The problem guarantees that the island is continuous and fully connected, so we do not need to handle multiple disconnected land masses.
Approaches
A naive, brute-force approach would involve examining each land cell and checking all four sides to see if it borders water or is on the grid boundary. We would sum all sides that meet this condition. While this works, it requires checking each cell individually and its neighbors, resulting in repeated calculations and slightly redundant logic.
The key observation for an optimal solution is that each land cell contributes 4 to the perimeter minus 2 for each adjacent land cell. Instead of checking all cells multiple times, we can iterate through the grid once, and for each land cell, subtract 2 from the perimeter for each adjacent land cell that has already been counted (top and left neighbors suffice). This reduces repeated neighbor checking and keeps the logic clean, achieving O(mn) time complexity with minimal extra space.
| Approach | Time Complexity | Space Complexity | Notes |
|---|---|---|---|
| Brute Force | O(mn) | O(1) | Check all four neighbors of every land cell |
| Optimal | O(mn) | O(1) | Count 4 for each land cell and subtract 2 for each neighbor already processed |
Algorithm Walkthrough
- Initialize a
perimetervariable to zero. This will accumulate the total perimeter of the island. - Iterate through each row
iand columnjof the grid. - If the current cell
grid[i][j]is land (1), start with a contribution of 4 to the perimeter. - Check the cell above (
i-1, j) and to the left (i, j-1). For each neighboring land cell, subtract 2 from the perimeter. We only need top and left because bottom and right will be checked in later iterations. - Continue iterating until all cells have been processed.
- Return the final
perimetervalue.
Why it works: Each land cell initially contributes four sides, representing the maximum possible perimeter for that cell. For each shared side with an adjacent land cell already counted, we subtract two, once for the current cell and once implicitly for the neighbor, ensuring each shared edge is only counted once. This guarantees correctness.
Python Solution
from typing import List
class Solution:
def islandPerimeter(self, grid: List[List[int]]) -> int:
perimeter = 0
rows = len(grid)
cols = len(grid[0])
for i in range(rows):
for j in range(cols):
if grid[i][j] == 1:
perimeter += 4
if i > 0 and grid[i-1][j] == 1:
perimeter -= 2
if j > 0 and grid[i][j-1] == 1:
perimeter -= 2
return perimeter
The implementation iterates through the grid once. Each land cell contributes four sides, then we check only the top and left neighbors. If either neighbor is land, it means this side is shared, so we subtract 2. This approach avoids double-counting shared edges and ensures O(mn) time complexity without using extra space beyond a few counters.
Go Solution
func islandPerimeter(grid [][]int) int {
perimeter := 0
rows := len(grid)
cols := len(grid[0])
for i := 0; i < rows; i++ {
for j := 0; j < cols; j++ {
if grid[i][j] == 1 {
perimeter += 4
if i > 0 && grid[i-1][j] == 1 {
perimeter -= 2
}
if j > 0 && grid[i][j-1] == 1 {
perimeter -= 2
}
}
}
}
return perimeter
}
The Go solution mirrors the Python implementation. Differences include using len(grid) to determine dimensions, zero-based for-loops instead of Python range, and explicitly managing integer addition. No extra slices or maps are required.
Worked Examples
Example 1:
Grid:
[[0,1,0,0],
[1,1,1,0],
[0,1,0,0],
[1,1,0,0]]
Step by step:
| i | j | grid[i][j] | perimeter | notes |
|---|---|---|---|---|
| 0 | 1 | 1 | 4 | no neighbors above/left |
| 1 | 0 | 1 | 8 | no neighbors above/left |
| 1 | 1 | 1 | 12 | neighbor above -> -2, left -> -2 => total perimeter now 12 |
| 1 | 2 | 1 | 16 | left neighbor -> -2, top neighbor -> 0 (already subtracted) |
| 2 | 1 | 1 | 18 | top neighbor -> -2, left neighbor 0 => perimeter = 16 |
| 3 | 0 | 1 | 20 | top neighbor 0, left neighbor 0 |
| 3 | 1 | 1 | 24 | top neighbor -> -2, left neighbor -> -2 => perimeter = 20 |
Final perimeter = 16
Example 2: [[1]] → perimeter = 4
Example 3: [[1,0]] → perimeter = 4
Complexity Analysis
| Measure | Complexity | Explanation |
|---|---|---|
| Time | O(mn) | We iterate through each cell once |
| Space | O(1) | Only a few integer variables are used, no extra data structures |
The solution is efficient because each cell is processed exactly once, and neighbor checks are limited to two directions.
Test Cases
# test cases
assert Solution().islandPerimeter([[0,1,0,0],[1,1,1,0],[0,1,0,0],[1,1,0,0]]) == 16 # example 1
assert Solution().islandPerimeter([[1]]) == 4 # single cell
assert Solution().islandPerimeter([[1,0]]) == 4 # horizontal single row
assert Solution().islandPerimeter([[0,1]]) == 4 # horizontal single row, land at end
assert Solution().islandPerimeter([[1],[0]]) == 4 # vertical single column
assert Solution().islandPerimeter([[1,1],[1,1]]) == 8 # small square island
assert Solution().islandPerimeter([[0,0,0],[0,1,0],[0,0,0]]) == 4 # land surrounded by water
| Test | Why |
|---|---|
| example 1 | tests general multiple-cell island |
| single cell | smallest possible island |
| horizontal single row | island at start or end of row |
| vertical single column | island at top or bottom of column |
| small square | island with all neighbors filled |
| surrounded by water | island not touching edges |
Edge Cases
The first edge case is a single land cell in a grid, which could be at the edge or center. The perimeter must be 4, and our neighbor check ensures no subtraction occurs since no adjacent cells exist.
The second edge case is a line of land cells, either horizontal or vertical. Each cell in the middle shares two sides with neighbors, and the subtraction of 2 for each adjacent cell ensures the perimeter is calculated correctly.
The third edge case is an island that touches the boundaries of the grid. Our implementation correctly handles i == 0 or j == 0 without attempting to access negative indices, preventing out-of-bounds errors.
This approach handles all guaranteed input conditions efficiently and correctly.