【刷题之路Ⅲ】LeetCode 827. 最大人工岛

这篇具有很好参考价值的文章主要介绍了【刷题之路Ⅲ】LeetCode 827. 最大人工岛。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

一、题目描述

二、解题思路及代码

读完题目我们会发现,这道题正来做其实是很难的,那我们就反着做。

我们可以将思路转化为由数字是0的格子出发,统计与它相邻的岛屿的面积,依次遍历完所有的0格子,就能得到最大的面积了:

【刷题之路Ⅲ】LeetCode 827. 最大人工岛,刷题之路——困难及以上,leetcode,算法,职场和发展

统计面积的操作使用bfs来做,但是如果直接这样做我们会发现,存在许多的重复计算,就比如下面这个例子:

【刷题之路Ⅲ】LeetCode 827. 最大人工岛,刷题之路——困难及以上,leetcode,算法,职场和发展

右上角和左下角的两个0的相邻岛屿其实是同一个,如果这种重复相邻的岛屿很多的话,很可能就会超时,

我这里已经帮大家试验过了,直接计算的话,是会超时的:

代码:

// 开始解题:
// 方法——bfs(暴力)
class Solution {
public:
    // 向量数组
    int dx[4] = { -1, 1, 0, 0 }, dy[4] = { 0, 0, -1, 1 };
    int bfs(vector<vector<int>>& grid, int row, int col) {
        int n = grid.size();
        vector<vector<bool>> vis(n, vector<bool>(n, false));
        vis[row][col] = true;
        int ret = 1;
        queue<pair<int, int>> q;
        q.push({ row, col });
        while (!q.empty()) {
            int a = q.front().first, b = q.front().second;
            q.pop();
            for (int k = 0; k < 4; k++) {
                int x = a + dx[k], y = b + dy[k];
                if (x >= 0 && x < n && y >= 0 && y < n && !vis[x][y] && grid[x][y] == 1) {
                    ret++;
                    vis[x][y] = true;
                    q.push({ x, y });
                }
            }
        }
        return ret;
    }
    int largestIsland(vector<vector<int>>& grid) {
        int n = grid.size();
        int ret = 1;
        int flag = 0; // 标记是否出现了数字0
        for (int i = 0; i < n; i++) {
            for (int j = 0; j < n; j++) {
                if (grid[i][j] == 0) {
                    flag = 1;
                    for (int k = 0; k < 4; k++) {
                        int x = i + dx[k], y = j + dy[k];
                        if (x >= 0 && x < n && y >= 0 && y < n && grid[x][y] == 1) {
                            ret = max(ret, bfs(grid, i, j));
                            break; // 因为这里是直接计算的,所以只需要计算一次即可,其他的全是重复计算
                        }
                    }
                }
            }
        }
        if (flag) {
            return ret;
        }
        return n * n; // 没有0就直接返回整个矩阵的面积
    }
};

运行结果:

【刷题之路Ⅲ】LeetCode 827. 最大人工岛,刷题之路——困难及以上,leetcode,算法,职场和发展

那我们该怎么解决这个重复计算的问题呢?

我们可以在bfs的过程中对每个岛屿进行编号(其实是对一个岛屿的每个格子都编号),然后用哈希表来记录每个岛屿编号对应的面积。

开始时先对每个岛屿进行编号并统计面积,然后在枚举数字为0的格子,计算与它相邻(上下左右四个方向相邻)的岛屿的面积。

因为我们现在不是直接计算了,而是直接加上岛屿的面积,所以还有可能会出现重复计算一个岛屿的情况:

例如:

【刷题之路Ⅲ】LeetCode 827. 最大人工岛,刷题之路——困难及以上,leetcode,算法,职场和发展

我们在枚举0的上下左右四方方向时,如上图左边和下边相邻的岛屿是同一个,这就重复计算了,所以我们还得用一个哈希表来记录每个0格子累加过的岛屿编号,从而避免重复计算。

代码:

// 开始解题:
// 方法——标记岛屿 + bfs
class Solution {
public:
    int area = 0; // 统计某个岛屿的面积
    int number = 1; // 岛屿的编号
    int n = 0;
    int dx[4] = { -1, 1, 0, 0 }, dy[4] = { 0, 0, -1, 1 };
    int vis[510][510]; // 标记每个岛屿是否被访问过, 访问过就加上编号,表示gird[i][j格子]所在的岛屿的标号为vis[i][j]
    unordered_map<int, int> islan; // 存储每个编号对应的岛的面积

    void bfs(vector<vector<int>>& grid, int row, int col) {
        vis[row][col] = number;
        queue<pair<int, int>> q;
        q.push({ row, col});
        while (!q.empty()) {
            int a = q.front().first;
            int b = q.front().second;
            q.pop();
            for (int k = 0; k < 4; k++) {
                int x = a + dx[k], y = b + dy[k];
                if (x >= 0 && x < n && y >= 0 && y < n && !vis[x][y] && grid[x][y] == 1) {
                    area++;
                    vis[x][y] = number;
                    q.push({ x, y});
                }
            }
        }
        islan[number] = area;
    }

    int largestIsland(vector<vector<int>>& grid) {
        n = grid.size();
        // 先将每个岛屿标记
        for (int i = 0; i < n; i++) {
            for (int j = 0; j < n; j++) {
                if (grid[i][j] == 1 && !vis[i][j]) {
                    area = 1;
                    bfs(grid, i, j);
                    number++; // 计算完一个岛屿,umber++
                }
            }
        }

        // 再计算最大面积
        int ret = 0;
        int flag = 0; // 标记是否找到0
        for (int i = 0; i < n; i++) {
            for (int j = 0; j < n; j++){
                if (grid[i][j] == 0) {
                    flag = 1;
                    unordered_set<int> hash;
                    int temp_area = 1; // 面积从1开始,表示0格子的面积
                    for (int k = 0; k < 4; k++) {
                        int x = i + dx[k], y = j + dy[k];
                        if (x >= 0 && x < n && y >= 0 && y < n && grid[x][y] == 1) {
                            if (!hash.count(vis[x][y])) {
                                temp_area += islan[vis[x][y]];
                                hash.insert(vis[x][y]);
                            }

                        }
                    }
                    ret = max(ret, temp_area);
                }
            }
        }
        if (flag) {
            return ret;
        }
        return n * n; // 如果没有发现0,就直接返回整个矩阵的面积
    }
};

运行结果:

【刷题之路Ⅲ】LeetCode 827. 最大人工岛,刷题之路——困难及以上,leetcode,算法,职场和发展文章来源地址https://www.toymoban.com/news/detail-800229.html

到了这里,关于【刷题之路Ⅲ】LeetCode 827. 最大人工岛的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 【leetcode刷题之路】剑指Offer(3)——搜索与回溯算法

    7 搜索与回溯算法 7.1 【BFS】剑指 Offer 32 - I - 从上到下打印二叉树 https://leetcode.cn/problems/cong-shang-dao-xia-da-yin-er-cha-shu-lcof/   这里借助队列来实现广度优先遍历,由于需要访问每一层的节点,而且这一层访问才可以访问下一层,所以可以考虑队列的先进先出,先把每一层的节

    2024年02月13日
    浏览(44)
  • 【leetcode刷题之路】剑指Offer(4)——分治+排序算法+动态规划

    8 分治算法 8.1 【递归】剑指 Offer 07 - 重建二叉树 https://leetcode.cn/problems/zhong-jian-er-cha-shu-lcof/   前序遍历是根左右,中序遍历是左根右,这也就意味着前序遍历的第一个节点是整棵树的根节点,顺着这个节点找到它在中序遍历中的位置,即为in_root,那么in_root左边的都在左子

    2024年02月11日
    浏览(43)
  • 【leetcode刷题之路】面试经典150题(2)——双指针+滑动窗口+矩阵

    2 双指针 2.1 【双指针】验证回文串 题目地址:https://leetcode.cn/problems/valid-palindrome/description/?envType=study-plan-v2envId=top-interview-150   详见代码。 2.2 【双指针】判断子序列 题目地址:https://leetcode.cn/problems/is-subsequence/description/?envType=study-plan-v2envId=top-interview-150   双指针挨个遍

    2024年02月19日
    浏览(39)
  • 【leetcode刷题之路】初级算法(2)——链表+树+排序和搜索+动态规划

    3.1 【链表】删除链表中的节点 https://leetcode.cn/problems/delete-node-in-a-linked-list/ 给出的就是要删除的那个节点,直接前后移动就行了。 3.2 【双指针】删除链表的倒数第 N 个结点 https://leetcode.cn/problems/remove-nth-node-from-end-of-list/ 利用双指针left和right,首先让right遍历n个节点,再让两

    2024年02月10日
    浏览(38)
  • 老卫带你学---leetcode刷题(215. 数组中的第K个最大元素)

    给定整数数组 nums 和整数 k,请返回数组中第 k 个最大的元素。 请注意,你需要找的是数组排序后的第 k 个最大的元素,而不是第 k 个不同的元素。 你必须设计并实现时间复杂度为 O(n) 的算法解决此问题。 堆排序 对每个元素入堆,然后pop出来k-1个 这里需要注意,默认堆为最

    2024年02月07日
    浏览(34)
  • LeetCode刷题 | 1143. 最长公共子序列、1035. 不相交的线、53. 最大子数组和

    给定两个字符串  text1  和  text2 ,返回这两个字符串的最长  公共子序列  的长度。如果不存在  公共子序列  ,返回  0  。 一个字符串的  子序列   是指这样一个新的字符串:它是由原字符串在不改变字符的相对顺序的情况下删除某些字符(也可以不删除任何字符)后

    2024年02月12日
    浏览(34)
  • LeetCode刷题笔记【23】:贪心算法专题-1(分发饼干、摆动序列、最大子序和)

    贪心的本质是选择每一阶段的局部最优,从而达到全局最优。 例如,有一堆钞票,你可以拿走十张,如果想达到最大的金额,你要怎么拿? 指定每次拿最大的,最终结果就是拿走最大数额的钱。 每次拿最大的就是局部最优,最后拿走最大数额的钱就是推出全局最优。 感觉像

    2024年02月09日
    浏览(42)
  • 【leetcode刷题之路】面试经典150题(8)——位运算+数学+一维动态规划+多维动态规划

    20 位运算 20.1 【位运算】二进制求和 题目地址:https://leetcode.cn/problems/add-binary/description/?envType=study-plan-v2envId=top-interview-150   按位逆序运算。 20.2 【位运算】颠倒二进制位 题目地址:https://leetcode.cn/problems/reverse-bits/description/?envType=study-plan-v2envId=top-interview-150   详见代码

    2024年04月16日
    浏览(61)
  • leetcode刷题电话号码的字母组合(人工智能解答版本)

    一开始想用暴力破解的方法来进行解题,就是循环。但是想到随着数字的增多,循环行不通。想到最近使用的一个人工智能助手,于是我把题目发送给了它,直接给出了递归的解决方法。递归分为两个条件,一个就是当列表中的元素的数目达到了数字的个数,那么将列表中的

    2024年02月22日
    浏览(34)
  • LeetCode刷题笔记【25】:贪心算法专题-3(K次取反后最大化的数组和、加油站、分发糖果)

    参考前文 参考文章: LeetCode刷题笔记【23】:贪心算法专题-1(分发饼干、摆动序列、最大子序和) LeetCode刷题笔记【24】:贪心算法专题-2(买卖股票的最佳时机II、跳跃游戏、跳跃游戏II) LeetCode链接:https://leetcode.cn/problems/maximize-sum-of-array-after-k-negations/description/ 首先 sor

    2024年02月09日
    浏览(30)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包