Fading Coder

One Final Commit for the Last Sprint

Home > Tech > Content

Grid-Based Island Problems

Tech May 15 1

Counting Islands in a Grid

Given a 2D grid consisting of '1's (land) and '0's (water), we need to count the number of islands. An island is surrounded by water and is formed by connecting adjacent lands horizontally or vertically. We can assume all four edges of the grid are surrounded by water.

Example 1:

Input:  
11110  
11010  
11000  
00000

Output: 1

Example 2:

Input:  
11000  
11000  
00100  
00011

Output: 3

Solution using Depth-First Search:


function countIslands(matrix) {
    if (!matrix || matrix.length === 0) return 0;
    
    const rows = matrix.length;
    const cols = matrix[0].length;
    let islandCount = 0;
    
    for (let i = 0; i < rows; i++) {
        for (let j = 0; j < cols; j++) {
            if (matrix[i][j] === '1') {
                islandCount++;
                exploreIsland(matrix, i, j);
            }
        }
    }
    
    return islandCount;
}

function exploreIsland(matrix, x, y) {
    // Check boundaries and if current cell is water
    if (x < 0 || x >= matrix.length || y < 0 || y >= matrix[0].length || matrix[x][y] === '0') {
        return;
    }
    
    // Mark current cell as visited
    matrix[x][y] = '0';
    
    // Recursively visit all adjacent cells
    exploreIsland(matrix, x + 1, y);
    exploreIsland(matrix, x - 1, y);
    exploreIsland(matrix, x, y + 1);
    exploreIsland(matrix, x, y - 1);
}

Solution using Breadth-First Search:


function countIslands(matrix) {
    if (!matrix || matrix.length === 0) return 0;
    
    const rows = matrix.length;
    const cols = matrix[0].length;
    let islandCount = 0;
    const queue = [];
    
    for (let i = 0; i < rows; i++) {
        for (let j = 0; j < cols; j++) {
            if (matrix[i][j] === '1') {
                islandCount++;
                matrix[i][j] = '0';
                queue.push([i, j]);
                
                while (queue.length > 0) {
                    const [x, y] = queue.shift();
                    
                    // Check all four directions
                    if (x > 0 && matrix[x-1][j] === '1') {
                        queue.push([x-1, j]);
                        matrix[x-1][j] = '0';
                    }
                    if (x < rows-1 && matrix[x+1][j] === '1') {
                        queue.push([x+1, j]);
                        matrix[x+1][j] = '0';
                    }
                    if (y > 0 && matrix[x][y-1] === '1') {
                        queue.push([x, y-1]);
                        matrix[x][y-1] = '0';
                    }
                    if (y < cols-1 && matrix[x][y+1] === '1') {
                        queue.push([x, y+1]);
                        matrix[x][y+1] = '0';
                    }
                }
            }
        }
    }
    
    return islandCount;
}

Finding the Farthest Ocean from Land

Given an N x N grid where each cell is marked as 0 (ocean) or 1 (land), we need to find the ocean cell that is farthest from any land cell. The distance is defined as the Manhattan distance: |x0 - x1| + |y0 - y1|.

If the grid contains only land or only ocean, we should return -1.

Example 1:

Input: [[1,0,1],[0,0,0],[1,0,1]]
Output: 2
Explanation: 
The ocean cell at (1, 1) has the maximum distance of 2 from all land cells.

Example 2:

Input: [[1,0,0],[0,0,0],[0,0,0]]
Output: 4
Explanation: 
The ocean cell at (2, 2) has the maximum distance of 4 from all land cells.

Solution using Multi-source BFS:


function findMaxDistance(grid) {
    const size = grid.length;
    const directions = [[0, 1], [1, 0], [0, -1], [-1, 0]];
    
    // Check if grid is all land or all ocean
    let hasLand = false, hasOcean = false;
    for (let i = 0; i < size; i++) {
        for (let j = 0; j < size; j++) {
            if (grid[i][j] === 1) hasLand = true;
            if (grid[i][j] === 0) hasOcean = true;
        }
    }
    if (!hasLand || !hasOcean) return -1;
    
    // Initialize distance matrix and queue
    const distance = new Array(size).fill().map(() => new Array(size).fill(-1));
    const queue = [];
    
    // Add all land cells to the queue
    for (let i = 0; i < size; i++) {
        for (let j = 0; j < size; j++) {
            if (grid[i][j] === 1) {
                queue.push([i, j]);
                distance[i][j] = 0;
            }
        }
    }
    
    // Perform BFS
    while (queue.length > 0) {
        const [x, y] = queue.shift();
        
        for (const [dx, dy] of directions) {
            const newX = x + dx;
            const newY = y + dy;
            
            if (newX >= 0 && newX < size && newY >= 0 && newY < size && distance[newX][newY] === -1) {
                distance[newX][newY] = distance[x][y] + 1;
                queue.push([newX, newY]);
            }
        }
    }
    
    // Find the maximum distance
    let maxDist = 0;
    for (let i = 0; i < size; i++) {
        for (let j = 0; j < size; j++) {
            if (grid[i][j] === 0) {
                maxDist = Math.max(maxDist, distance[i][j]);
            }
        }
    }
    
    return maxDist;
}

Counting Closed Islands

Given a 2D grid where each cell is either land (0) or water (1), we need to count the number of closed islands. A closed island is an island completely surrounded by water, meaning all adjacent cells (up, down, left, right) of the island's perimeter are water.

Example 1:

Input: [[1,1,1,1,1,1,1,0],[1,0,0,0,0,1,1,0],[1,0,1,0,1,1,1,0],[1,0,0,0,0,1,0,1],[1,1,1,1,1,1,1,0]]
Output: 2
Explanation: 
The gray regions are closed islands as they are completely surrounded by water.

Example 2:

Input: [[0,0,1,0,0],[0,1,0,1,0],[0,1,1,1,0]]
Output: 1

Solution using DFS:


function countClosedIslands(grid) {
    const rows = grid.length;
    const cols = grid[0].length;
    let count = 0;
    
    function isClosed(x, y) {
        // If we reach the boundary, this island is not closed
        if (x < 0 || x >= rows || y < 0 || y >= cols) {
            return false;
        }
        
        // If it's water, return true
        if (grid[x][y] === 1) {
            return true;
        }
        
        // Mark current cell as visited
        grid[x][y] = 1;
        
        // Check all four directions
        const up = isClosed(x - 1, y);
        const down = isClosed(x + 1, y);
        const left = isClosed(x, y - 1);
        const right = isClosed(x, y + 1);
        
        // The island is closed only if all directions are closed
        return up && down && left && right;
    }
    
    for (let i = 0; i < rows; i++) {
        for (let j = 0; j < cols; j++) {
            if (grid[i][j] === 0) {
                if (isClosed(i, j)) {
                    count++;
                }
            }
        }
    }
    
    return count;
}

Alternative Solution using BFS:


function countClosedIslands(grid) {
    const rows = grid.length;
    const cols = grid[0].length;
    const directions = [[0, 1], [1, 0], [0, -1], [-1, 0]];
    let count = 0;
    
    for (let i = 0; i < rows; i++) {
        for (let j = 0; j < cols; j++) {
            if (grid[i][j] === 0) {
                let isClosed = true;
                const queue = [[i, j]];
                grid[i][j] = 1; // Mark as visited
                
                while (queue.length > 0) {
                    const [x, y] = queue.shift();
                    
                    // If we're at the boundary, this island is not closed
                    if (x === 0 || x === rows - 1 || y === 0 || y === cols - 1) {
                        isClosed = false;
                    }
                    
                    // Check all four directions
                    for (const [dx, dy] of directions) {
                        const newX = x + dx;
                        const newY = y + dy;
                        
                        if (newX >= 0 && newX < rows && newY >= 0 && newY < cols && grid[newX][newY] === 0) {
                            queue.push([newX, newY]);
                            grid[newX][newY] = 1; // Mark as visited
                        }
                    }
                }
                
                if (isClosed) {
                    count++;
                }
            }
        }
    }
    
    return count;
}

Related Articles

Understanding Strong and Weak References in Java

Strong References Strong reference are the most prevalent type of object referencing in Java. When an object has a strong reference pointing to it, the garbage collector will not reclaim its memory. F...

Comprehensive Guide to SSTI Explained with Payload Bypass Techniques

Introduction Server-Side Template Injection (SSTI) is a vulnerability in web applications where user input is improper handled within the template engine and executed on the server. This exploit can r...

Implement Image Upload Functionality for Django Integrated TinyMCE Editor

Django’s Admin panel is highly user-friendly, and pairing it with TinyMCE, an effective rich text editor, simplifies content management significantly. Combining the two is particular useful for bloggi...

Leave a Comment

Anonymous

◎Feel free to join the discussion and share your thoughts.