每日算法系列【LeetCode 827】最大人工岛

简介: 每日算法系列【LeetCode 827】最大人工岛

题目描述

在二维地图上, 0 代表海洋, 1 代表陆地,我们最多只能将一格 0 海洋变成 1 变成陆地。

进行填海之后,地图上最大的岛屿面积是多少?(上、下、左、右四个方向相连的 1 可形成岛屿)

示例1

输入:
[[1, 0], [0, 1]]
输出:
3
解释:
将一格 0 变成 1 ,最终连通两个小岛得到面积为 3 的岛屿。

示例2

输入:
[[1, 1], [1, 0]]
输出:
4
解释:
将一格 0 变成 1 ,岛屿的面积扩大为 4 。

示例3

输入:
[[1, 1], [1, 1]]
输出:
4
解释:
没有 0 可以让我们变成 1 ,面积依然为 4 。

提示

  • 1 <= grid.length = grid[0].length <= 50
  • 0 <= grid[i][j] <= 1

题解

没有做过这种类型题目的强烈建议自己动手实现一遍,对提升代码能力有很大帮助。

这题虽然是 hard 难度,但其实没有什么算法,只用到了 dfs 求连通块而已。我们只需要知道填充了一个 0 之后,它上下左右跟它相邻的 4 块连通块是多大。

首先普及一下什么是连通块,就是一块由 1 组成的区域,其中任意两块 1 都可以由一条 1 组成的路径走过去(只能上下左右走)。那么这题我们遍历所有的 0 ,把它四周的连通块大小加起来就是填充了这块 0 之后的连通块大小了。那么问题是怎么知道它周围连通块的大小呢?

首先我们得求出所有连通块的大小,然后存下来,这就得用到 dfs 了。

用二维数组 index (初始化为 -1)记录方块是否被搜索过。然后遍历所有的方块,如果是 1 ,并且 index 为 -1 (也就是没被搜索过),那么它的 index 设为 1 ,表示被搜索过了。然后从它开始向四周进行 dfs ,直到跟它相连的所有 1 的连通块都被搜索完毕。这时候整块连通块里面的 1 方块的 index 都被设成了 1 ,就算以后被遍历到了也不会被搜索了。那么大小怎么记录呢?只需要设置一个变量 cnt 初始为 1 ,然后 dfs 的时候遇到一个未被搜索的块就加 1 ,最后 cnt 就是当前连通块的大小了。

光知道了每个连通块的大小还不行,对于一个 0 块,四周的 1 方块万一属于同一个连通块怎么办?得区分它们,不然就会被重复计算。所以在上面的 dfs 之前,给那块连通块一个唯一的编号(从 0 开始),遇到下一个连通块就加 1 。这样 index 数组就可以用来存连通块的编号了,同时还能表示方块是否被搜索过。

具体的细节还得看代码,有很多实现的技巧,当然我写的还有一些优化余地。

代码

c++

class Solution {
public:
    static const int N = 55;
    int dx[4] = {0, 0, 1, -1};
    int dy[4] = {1, -1, 0, 0};
    int index[N][N], area[N*N], flag[N*N];
    int m, n;
    int largestIsland(vector<vector<int>>& grid) {
        m = grid.size();
        n = grid[0].size();
        memset(index, -1, sizeof index);
        memset(area, 0, sizeof area);
        memset(flag, 0, sizeof flag);
        int res = 0, idx = -1;
        for (int i = 0; i < m; ++i) {
            for (int j = 0; j < n; ++j) {
                if (grid[i][j] == 1 && index[i][j] == -1) {
                    int cnt = 1;
                    index[i][j] = ++idx;
                    dfs(i, j, idx, cnt, grid);
                    area[idx] = cnt;
                    res = max(res, cnt);
                }
            }
        }
        for (int x = 0; x < m; ++x) {
            for (int y = 0; y < n; ++y) {
                if (grid[x][y] == 0) {
                    int tmp = 1;
                    for (int i = 0; i < 4; ++i) {
                        int nx = x + dx[i], ny = y + dy[i];
                        if (inside(nx, ny) && grid[nx][ny] == 1 && !flag[index[nx][ny]]) {
                            flag[index[nx][ny]] = 1;
                            tmp += area[index[nx][ny]];
                        }
                    }
                    for (int i = 0; i < 4; ++i) {
                        int nx = x + dx[i], ny = y + dy[i];
                        if (inside(nx, ny) && grid[nx][ny] == 1 && flag[index[nx][ny]]) {
                            flag[index[nx][ny]] = 0;
                        }
                    }
                    res = max(res, tmp);
                }
            }
        }
        return res;
    }
    bool inside(int x, int y) {
        return 0 <= x && x < m && 0 <= y && y < n;
    }
    void dfs(int x, int y, int idx, int& cnt, vector<vector<int>>& grid) {
        for (int i = 0; i < 4; ++i) {
            int nx = x + dx[i], ny = y + dy[i];
            if (inside(nx, ny) && grid[nx][ny] == 1 && index[nx][ny] == -1) {
                index[nx][ny] = idx;
                dfs(nx, ny, idx, ++cnt, grid);
            }
        }
    }
};

后记

dfs 求连通块是常规操作,必须要学会,很考验代码功底,要细心,不然很容易写错。

相关文章
|
1月前
|
算法
Leetcode 初级算法 --- 数组篇
Leetcode 初级算法 --- 数组篇
38 0
|
12天前
|
存储 算法 Java
leetcode算法题-有效的括号(简单)
【11月更文挑战第5天】本文介绍了 LeetCode 上“有效的括号”这道题的解法。题目要求判断一个只包含括号字符的字符串是否有效。有效字符串需满足左括号必须用相同类型的右括号闭合,并且左括号必须以正确的顺序闭合。解题思路是使用栈数据结构,遍历字符串时将左括号压入栈中,遇到右括号时检查栈顶元素是否匹配。最后根据栈是否为空来判断字符串中的括号是否有效。示例代码包括 Python 和 Java 版本。
|
1月前
|
算法
每日一道算法题(Leetcode 20)
每日一道算法题(Leetcode 20)
23 2
|
2月前
|
机器学习/深度学习 算法 Python
群智能算法:深入解读人工水母算法:原理、实现与应用
近年来,受自然界生物行为启发的优化算法备受关注。人工水母算法(AJSA)模拟水母在海洋中寻找食物的行为,是一种新颖的优化技术。本文详细解读其原理及实现步骤,并提供代码示例,帮助读者理解这一算法。在多模态、非线性优化问题中,AJSA表现出色,具有广泛应用前景。
WK
|
2月前
|
机器学习/深度学习 自然语言处理 算法
PSO算法和人工神经网络有什么不同
PSO算法(粒子群优化)与人工神经网络(ANN)在原理、应用及优化方式上差异显著。PSO模拟鸟群行为,通过粒子协作在解空间中搜索最优解;而ANN模仿大脑神经元结构,通过训练学习输入输出映射,适用于模式识别、图像处理等领域。PSO主要用于优化问题,实时性高,结果直观;ANN则在处理复杂非线性关系方面更强大,但结构复杂,训练耗时长,结果解释性较差。实际应用中需根据需求选择合适技术。
WK
26 0
|
3月前
|
算法 Java
LeetCode经典算法题:矩阵中省份数量经典题目+三角形最大周长java多种解法详解
LeetCode经典算法题:矩阵中省份数量经典题目+三角形最大周长java多种解法详解
51 6
|
3月前
|
人工智能 算法 Java
LeetCode经典算法题:井字游戏+优势洗牌+Dota2参议院java解法
LeetCode经典算法题:井字游戏+优势洗牌+Dota2参议院java解法
50 1
|
3月前
|
存储 算法 Java
LeetCode经典算法题:预测赢家+香槟塔java解法
LeetCode经典算法题:预测赢家+香槟塔java解法
60 1
|
3月前
|
存储 算法 数据可视化
【Python】实现二维装箱Bottom-Left算法及用人工蜂群算法改进
本文介绍了二维装箱问题的Bottom-Left算法,并提供了Python实现,包括主函数、装箱顺序、重叠检测、最终位置计算等,同时指出了算法的缺点并提出了使用人工蜂群算法进行改进的方法,最后提供了完整代码的下载链接。
72 1
|
3月前
|
存储 算法 Java
LeetCode经典算法题:二叉树遍历(递归遍历+迭代遍历+层序遍历)以及线索二叉树java详解
LeetCode经典算法题:二叉树遍历(递归遍历+迭代遍历+层序遍历)以及线索二叉树java详解
79 0