leetcode (4): 连通域/岛屿问题

1. 200. 岛屿数量

这道题是经典的二维网格连通域问题,核心思路是深度优先搜索(DFS) 或广度优先搜索(BFS),遍历网格找到所有独立的陆地连通块(岛屿)。

解题原理

  • 遍历网格:逐个检查每个格子,如果当前格子是陆地('1'),说明找到一座新岛屿,岛屿数量 + 1。
  • 淹没连通陆地:找到陆地后,用 DFS/BFS 把所有相邻(上下左右)的连通陆地全部标记为水('0'),避免重复计数。
  • 统计结果:遍历完成后,统计的岛屿数量就是答案。
py 复制代码
#include <vector>
using namespace std;

class Solution {
public:
    int numIslands(vector<vector<char>>& grid) {
        // 空网格直接返回0
        if (grid.empty() || grid[0].empty()) return 0;
        
        int row = grid.size();    // 网格行数
        int col = grid[0].size(); // 网格列数
        int count = 0;            // 岛屿数量
        
        // 遍历每一个格子
        for (int i = 0; i < row; ++i) {
            for (int j = 0; j < col; ++j) {
                // 找到陆地,岛屿数+1
                if (grid[i][j] == '1') {
                    count++;
                    // DFS淹没当前岛屿所有连通陆地
                    dfs(grid, i, j, row, col);
                }
            }
        }
        return count;
    }

private:
    // DFS递归函数:淹没(i,j)位置及相邻的陆地
    void dfs(vector<vector<char>>& grid, int i, int j, int row, int col) {
        // 边界判断:超出网格范围 或 当前是水,直接返回
        if (i < 0 || i >= row || j < 0 || j >= col || grid[i][j] == '0') {
            return;
        }
        
        // 把当前陆地淹没为水
        grid[i][j] = '0';
        
        // 递归遍历上下左右四个方向
        dfs(grid, i - 1, j, row, col); // 上
        dfs(grid, i + 1, j, row, col); // 下
        dfs(grid, i, j - 1, row, col); // 左
        dfs(grid, i, j + 1, row, col); // 右
    }
};

2. 1020. 飞地的数量

给你一个大小为 m x n 的二进制矩阵 grid ,其中 0 表示一个海洋单元格、1 表示一个陆地单元格。

一次 移动 是指从一个陆地单元格走到另一个相邻(上、下、左、右)的陆地单元格或跨过 grid 的边界。

返回网格中 无法 在任意次数的移动中离开网格边界的陆地单元格的数量。

这道题和岛屿数量思路几乎一样,核心是:先把能接触边界的陆地全部淹没,剩下的陆地就是飞地

解题原理

1.飞地定义:无法到达网格边界的陆地

2.反向思维:

  • 先遍历四条边界上的所有陆地,把它们连通的所有陆地全部淹没(这些都不是飞地)。

  • 最后统计网格中剩下的陆地数量,就是答案。

  • 依然用 DFS 实现,逻辑简单易懂。

py 复制代码
#include <vector>
using namespace std;

class Solution {
public:
    int numEnclaves(vector<vector<int>>& grid) {
        if (grid.empty() || grid[0].empty()) return 0;
        int m = grid.size();    // 行数
        int n = grid[0].size(); // 列数

        // 1. 淹没【四条边界】上所有能连通的陆地
        // 左右两列(j=0 和 j=n-1)
        for (int i = 0; i < m; ++i) {
            if (grid[i][0] == 1) {
                dfs(grid, i, 0, m, n);
            }
            if (grid[i][n-1] == 1) {
                dfs(grid, i, n-1, m, n);
            }
        }
        // 上下两行(i=0 和 i=m-1)
        for (int j = 0; j < n; ++j) {
            if (grid[0][j] == 1) {
                dfs(grid, 0, j, m, n);
            }
            if (grid[m-1][j] == 1) {
                dfs(grid, m-1, j, m, n);
            }
        }

        // 2. 统计剩下的陆地 = 飞地数量
        int count = 0;
        for (int i = 0; i < m; ++i) {
            for (int j = 0; j < n; ++j) {
                if (grid[i][j] == 1) {
                    count++;
                }
            }
        }
        return count;
    }

private:
    // DFS:淹没陆地
    void dfs(vector<vector<int>>& grid, int i, int j, int m, int n) {
        // 越界 / 不是陆地,直接返回
        if (i < 0 || i >= m || j < 0 || j >= n || grid[i][j] == 0) {
            return;
        }
        // 淹没当前陆地
        grid[i][j] = 0;
        // 上下左右
        dfs(grid, i-1, j, m, n);
        dfs(grid, i+1, j, m, n);
        dfs(grid, i, j-1, m, n);
        dfs(grid, i, j+1, m, n);
    }
};

3. 695. 岛屿的最大面积

  • 给你一个大小为 m x n 的二进制矩阵 grid 。
  • 岛屿 是由一些相邻的 1 (代表土地) 构成的组合,这里的「相邻」要求两个 1 必须在 水平或者竖直的四个方向上 相邻。你可以假设 grid 的四个边缘都被 0(代表水)包围着。
  • 岛屿的面积是岛上值为 1 的单元格的数目。计算并返回 grid 中最大的岛屿面积。如果没有岛屿,则返回面积为 0

这道题是岛屿数量的经典变种,核心思路:遍历每个岛屿,计算每座岛屿的面积,记录最大值

解题原理

  1. 遍历网格:逐个检查每个格子,遇到陆地(1)就开始计算这座岛屿的面积
  2. DFS 计算面积:用 DFS 淹没连通陆地,并统计当前岛屿的单元格数量(面积)。
  3. 记录最大值:每次算出一座岛屿的面积,就和全局最大值比较,更新最大面积
  4. 最终返回:遍历完所有岛屿,返回最大面积。
py 复制代码
#include <vector>
#include <algorithm>  // 用于 max 函数
using namespace std;

class Solution {
public:
   int maxAreaOfIsland(vector<vector<int>>& grid) {
       if (grid.empty() || grid[0].empty()) return 0;
       
       int m = grid.size();    // 行数
       int n = grid[0].size(); // 列数
       int maxArea = 0;        // 记录最大岛屿面积
       
       // 遍历所有格子
       for (int i = 0; i < m; ++i) {
           for (int j = 0; j < n; ++j) {
               // 找到陆地,计算当前岛屿面积
               if (grid[i][j] == 1) {
                   int currentArea = dfs(grid, i, j, m, n);
                   maxArea = max(maxArea, currentArea); // 更新最大值
               }
           }
       }
       return maxArea;
   }

private:
   // DFS:返回当前岛屿的面积
   int dfs(vector<vector<int>>& grid, int i, int j, int m, int n) {
       // 越界 / 是水,返回 0
       if (i < 0 || i >= m || j < 0 || j >= n || grid[i][j] == 0) {
           return 0;
       }
       
       // 淹没当前陆地(避免重复计算)
       grid[i][j] = 0;
       
       // 面积 = 当前1 + 上下左右的面积
       return 1 
            + dfs(grid, i-1, j, m, n)  // 上
            + dfs(grid, i+1, j, m, n)  // 下
            + dfs(grid, i, j-1, m, n)  // 左
            + dfs(grid, i, j+1, m, n); // 右
   }
};

4. 827. 最大人工岛

这道题是岛屿的最大面积进阶版,难度大,但思路非常清晰:先给每个岛屿编号 + 记录面积 → 遍历每个 0,看它四周能连接哪些不同岛屿 → 计算连接后的总面积 → 取最大值

解题核心原理

    1. 给岛屿编号:遍历所有陆地,用 DFS 给每座独立岛屿标上唯一编号(2,3,4...),同时用哈希表记录每个编号对应的岛屿面积。
    1. 尝试填海造陆:遍历每个海洋(0),查看它上下左右四个方向的相邻岛屿。
    • 收集不同编号的岛屿面积(避免重复加同一个岛)。
    • 把这些面积 + 1(填的这一格)就是造陆后的总面积。
  • 3.取最大值:对比所有可能的造陆结果,返回最大面积。

    • 如果全是陆地,直接返回网格总面积。
py 复制代码
#include <vector>
#include <unordered_set>
#include <unordered_map>
#include <algorithm>
using namespace std;

class Solution {
public:
    int largestIsland(vector<vector<int>>& grid) {
        int n = grid.size();
        // key:岛屿编号,value:岛屿面积
        unordered_map<int, int> area;
        int num = 2; // 岛屿编号从2开始(0海洋,1陆地)
        int max_area = 0;

        // 第一步:DFS给所有岛屿编号,记录面积
        for (int i = 0; i < n; ++i) {
            for (int j = 0; j < n; ++j) {
                if (grid[i][j] == 1) {
                    area[num] = dfs(grid, i, j, num, n);
                    max_area = max(max_area, area[num]); // 记录原始最大岛
                    num++;
                }
            }
        }

        // 第二步:遍历所有0,尝试填海造陆
        for (int i = 0; i < n; ++i) {
            for (int j = 0; j < n; ++j) {
                if (grid[i][j] == 0) {
                    unordered_set<int> visited; // 记录已访问的岛屿编号,防重复
                    int cur = 1; // 填当前这格0,面积+1

                    // 检查上下左右四个方向
                    for (auto& d : dirs) {
                        int x = i + d.first;
                        int y = j + d.second;
                        if (x >= 0 && x < n && y >= 0 && y < n) {
                            int id = grid[x][y];
                            if (id > 1 && !visited.count(id)) { // 是岛屿且没加过
                                visited.insert(id);
                                cur += area[id];
                            }
                        }
                    }
                    max_area = max(max_area, cur);
                }
            }
        }

        return max_area;
    }

private:
    // 上下左右方向数组
    vector<pair<int, int>> dirs = {{-1,0}, {1,0}, {0,-1}, {0,1}};

    // DFS:给岛屿编号,返回岛屿面积
    int dfs(vector<vector<int>>& grid, int i, int j, int num, int n) {
        // 越界 / 不是未编号的陆地,返回0
        if (i < 0 || i >= n || j < 0 || j >= n || grid[i][j] != 1) {
            return 0;
        }

        grid[i][j] = num; // 编号
        int area = 1;

        // 累加四个方向
        for (auto& d : dirs) {
            area += dfs(grid, i + d.first, j + d.second, num, n);
        }

        return area;
    }
};
相关推荐
Ulyanov2 小时前
像素迷宫:路径规划算法的可视化与实战
大数据·开发语言·python·算法
Mr_pyx2 小时前
【LeetCode Hot 100】 除自身以外数组的乘积(238题)多解法详解
算法·leetcode·职场和发展
Trouvaille ~2 小时前
零基础入门 LangChain 与 LangGraph(五):核心组件上篇——消息、提示词模板、少样本与输出解析
人工智能·算法·langchain·prompt·输入输出·ai应用·langgraph
MOON404☾3 小时前
Chapter 002. 线性回归
算法·回归·线性回归
故事和你913 小时前
洛谷-数据结构-1-3-集合3
数据结构·c++·算法·leetcode·贪心算法·动态规划·图论
春栀怡铃声3 小时前
【C++修仙录02】筑基篇:类和对象(上)
开发语言·c++·算法
ulias2123 小时前
leetcode热题 - 3
c++·算法·leetcode·职场和发展
实心儿儿4 小时前
Linux —— 进程概念 - 程序地址空间
linux·运维·算法
菜鸟丁小真4 小时前
LeetCode hot100-287.寻找重复数和994.腐烂的橘子
数据结构·算法·leetcode·知识点总结