Leetcode(695)——岛屿的最大面积

Leetcode(695)——岛屿的最大面积

题目

给你一个大小为 m × n m \times n m×n 的二进制矩阵 grid 。

岛屿 是由一些相邻的 1 (代表土地) 构成的组合,这里的「相邻」要求两个 1 必须在 水平或者竖直的四个方向上 相邻。你可以假设 grid 的四个边缘都被 0(代表水)包围着。

岛屿的面积是岛上值为 1 的单元格的数目。

计算并返回 grid 中最大的岛屿面积。如果没有岛屿,则返回面积为 0 。

示例 1:

在这里插入图片描述
输入:grid = [[0,0,1,0,0,0,0,1,0,0,0,0,0],[0,0,0,0,0,0,0,1,1,1,0,0,0],[0,1,1,0,1,0,0,0,0,0,0,0,0],[0,1,0,0,1,1,0,0,1,0,1,0,0],[0,1,0,0,1,1,0,0,1,1,1,0,0],[0,0,0,0,0,0,0,0,0,0,1,0,0],[0,0,0,0,0,0,0,1,1,1,0,0,0],[0,0,0,0,0,0,0,1,1,0,0,0,0]]
输出:6
解释:答案不应该是 11 ,因为岛屿只能包含水平或垂直这四个方向上的 1 。

示例 2:

输入:grid = [[0,0,0,0,0,0,0,0]]
输出:0

提示:

  • m == grid.length
  • n == grid[i].length
  • 1 1 1 <= m, n <= 50 50 50
  • grid[i][j] 为 0 0 0 1 1 1

题解

方法一:DFS(递归写法)

思路
  • 我们想知道网格中每个连通形状的面积,然后取最大值。
  • 如果我们在一个土地上,以 4 4 4 个方向探索与之相连的每一个土地(以及与这些土地相连的土地),那么探索过的土地总数将是该连通形状的面积。
  • 为了确保每个土地访问不超过一次,我们每次经过一块土地时,将这块土地的值置为 0 0 0。这样我们就不会多次访问同一土地。

​​  这里我们使用了一个小技巧,对于四个方向的遍历,可以创造一个数组 [-1, 0, 1, 0, -1],每相邻两位即为上下左右四个方向之一。

​​  在辅函数里,一个一定要注意的点是辅函数内递归搜索时,边界条件的判定。边界判定一般有两种写法,一种是先判定是否越界,只有在合法的情况下才进行下一步搜索(即判断放在调用递归函数前);另一种是不管三七二十一先进行下一步搜索,待下一步搜索开始时再判断是否合法(即判断放在辅函数第一行)。我们这里分别展示这两种写法。

代码实现

Leetcode 官方题解:

class Solution {
    int dfs(vector<vector<int>>& grid, int cur_i, int cur_j) {
        if (cur_i < 0 || cur_j < 0 || cur_i == grid.size() || cur_j == grid[0].size() || grid[cur_i][cur_j] != 1) {
            return 0;
        }
        grid[cur_i][cur_j] = 0;
        int di[4] = {0, 0, 1, -1};
        int dj[4] = {1, -1, 0, 0};
        int ans = 1;
        for (int index = 0; index != 4; ++index) {
            int next_i = cur_i + di[index], next_j = cur_j + dj[index];
            ans += dfs(grid, next_i, next_j);
        }
        return ans;
    }
public:
    int maxAreaOfIsland(vector<vector<int>>& grid) {
        int ans = 0;
        for (int i = 0; i != grid.size(); ++i) {
            for (int j = 0; j != grid[0].size(); ++j) {
                ans = max(ans, dfs(grid, i, j));
            }
        }
        return ans;
    }
};

我自己的:

class Solution {
    void DFS(vector<vector<int>>& grid, int x, int y, int& area){
        if(0 > x || x >= grid[0].size() || y >= grid.size() || 0 > y) return;
        if(grid[y][x] == 1){
            // 上下左右
            area += 1;
            grid[y][x] = 0; // 置为0防止再次访问该点
            DFS(grid, x-1, y, area);
            DFS(grid, x+1, y, area);
            DFS(grid, x, y-1, area);
            DFS(grid, x, y+1, area);
        }
    }
public:
    int maxAreaOfIsland(vector<vector<int>>& grid) {
        int ans = 0, area, yn = grid.size(), xn = grid[0].size();
        for(int y = 0; y < yn; y++){
            for(int x = 0; x < xn; x++){
                if(grid[y][x] == 1){
                    area = 0;
                    DFS(grid, x, y, area);
                    ans = ans < area? area: ans;
                }
            }
        }
        return ans;
    }
};
复杂度分析

时间复杂度 O ( m × n ) O(m×n) O(m×n)。其中 m m m 是给定网格中的行数, n n n 是列数。我们访问每个原本为1的网格最多一次。
空间复杂度 O ( m × n ) O(m \times n) O(m×n),递归的深度最大可能是整个网格的大小,因此最大可能使用 O ( m × n ) O(m \times n) O(m×n) 的栈空间。

方法二:DFS + 辅助栈(迭代写法)

思路

​​  原理与方法一相同,只是实现方式采用了迭代而不是递归,并使用栈辅助实现。

  • 方法一通过函数的调用来表示接下来想要遍历哪些土地,让下一层函数来访问这些土地。而方法二把接下来想要遍历的土地放在栈里,然后在取出这些土地的时候访问它们。
  • 访问每一片土地时,我们将对围绕它四个方向进行探索,找到还未访问的土地,加入到栈 stack \textit{stack} stack 中;
  • 另外,只要栈 stack \textit{stack} stack 不为空,就说明我们还有土地待访问,那么就从栈中取出一个元素并访问。
代码实现

Leetcode 官方题解:

class Solution {
public:
    int maxAreaOfIsland(vector<vector<int>>& grid) {
        int ans = 0;
        for (int i = 0; i != grid.size(); ++i) {
            for (int j = 0; j != grid[0].size(); ++j) {
                int cur = 0;
                stack<int> stacki;
                stack<int> stackj;
                stacki.push(i);
                stackj.push(j);
                while (!stacki.empty()) {
                    int cur_i = stacki.top(), cur_j = stackj.top();
                    stacki.pop();
                    stackj.pop();
                    if (cur_i < 0 || cur_j < 0 || cur_i == grid.size() || cur_j == grid[0].size() || grid[cur_i][cur_j] != 1) {
                        continue;
                    }
                    ++cur;
                    grid[cur_i][cur_j] = 0;
                    int di[4] = {0, 0, 1, -1};
                    int dj[4] = {1, -1, 0, 0};
                    for (int index = 0; index != 4; ++index) {
                        int next_i = cur_i + di[index], next_j = cur_j + dj[index];
                        stacki.push(next_i);
                        stackj.push(next_j);
                    }
                }
                ans = max(ans, cur);
            }
        }
        return ans;
    }
};

我自己的:

class Solution {
public:
    int maxAreaOfIsland(vector<vector<int>>& grid) {
        int ans = 0, area, yn = grid.size(), xn = grid[0].size();
        stack<pair<int, int>> island;
        pair<int, int> tmp;
        for(int y = 0; y < yn; y++){
            for(int x = 0; x < xn; x++){
                if(grid[y][x] == 1){
                    area = 0;
                    island.push(make_pair(y, x));
                    while(!island.empty()){
                        tmp.first = island.top().first;
                        tmp.second = island.top().second;
                        island.pop();
                        if(grid[tmp.first][tmp.second] != 1) continue;
                        grid[tmp.first][tmp.second] = 0;
                        area++;
                        if(tmp.second-1 >= 0) island.push(make_pair(tmp.first, tmp.second-1));
                        if(tmp.second+1 < xn) island.push(make_pair(tmp.first, tmp.second+1));
                        if(tmp.first-1 >= 0) island.push(make_pair(tmp.first-1, tmp.second));
                        if(tmp.first+1 < yn) island.push(make_pair(tmp.first+1, tmp.second));
                    }
                    ans = max(area, ans);
                }
            }
        }
        return ans;
    }
};
复杂度分析

时间复杂度 O ( m × n ) O(m \times n) O(m×n)。其中 m m m 是给定网格中的行数, n n n 是列数。我们访问每个原本为1的网格最多一次。
空间复杂度 O ( m × n ) O(m \times n) O(m×n),栈中最多会存放所有的土地,土地的数量最多为 m × n m \times n m×n 块,因此使用的空间为 O ( m × n ) O(m \times n) O(m×n)

方法三:BFS + 队列

思路

​​  把方法二中的栈改为队列,每次从队首取出土地,并将接下来想要遍历的土地放在队尾,就实现了广度优先搜索算法。

代码实现

Leetcode 官方题解:

class Solution {
public:
    int maxAreaOfIsland(vector<vector<int>>& grid) {
        int ans = 0;
        for (int i = 0; i != grid.size(); ++i) {
            for (int j = 0; j != grid[0].size(); ++j) {
                int cur = 0;
                queue<int> queuei;
                queue<int> queuej;
                queuei.push(i);
                queuej.push(j);
                while (!queuei.empty()) {
                    int cur_i = queuei.front(), cur_j = queuej.front();
                    queuei.pop();
                    queuej.pop();
                    if (cur_i < 0 || cur_j < 0 || cur_i == grid.size() || cur_j == grid[0].size() || grid[cur_i][cur_j] != 1)
                        continue;
                    ++cur;
                    grid[cur_i][cur_j] = 0;
                    int di[4] = {0, 0, 1, -1};
                    int dj[4] = {1, -1, 0, 0};
                    for (int index = 0; index != 4; ++index) {
                        int next_i = cur_i + di[index], next_j = cur_j + dj[index];
                        queuei.push(next_i);
                        queuej.push(next_j);
                    }
                }
                ans = max(ans, cur);
            }
        }
        return ans;
    }
};

我自己的:

class Solution {
public:
    int maxAreaOfIsland(vector<vector<int>>& grid) {
        int ans = 0, area, yn = grid.size(), xn = grid[0].size();
        queue<pair<int, int>> island;
        pair<int, int> tmp;
        for(int y = 0; y < yn; y++){
            for(int x = 0; x < xn; x++){
                if(grid[y][x] == 1){
                    area = 0;
                    island.push(make_pair(y, x));
                    while(!island.empty()){
                        tmp.first = island.front().first;
                        tmp.second = island.front().second;
                        island.pop();
                        if(grid[tmp.first][tmp.second] != 1) continue;
                        grid[tmp.first][tmp.second] = 0;
                        area++;
                        if(tmp.second-1 >= 0) island.push(make_pair(tmp.first, tmp.second-1));
                        if(tmp.second+1 < xn) island.push(make_pair(tmp.first, tmp.second+1));
                        if(tmp.first-1 >= 0) island.push(make_pair(tmp.first-1, tmp.second));
                        if(tmp.first+1 < yn) island.push(make_pair(tmp.first+1, tmp.second));
                    }
                    ans = max(area, ans);
                }
            }
        }
        return ans;
    }
};
复杂度分析

时间复杂度 O ( m × n ) O(m×n) O(m×n)。其中 m m m 是给定网格中的行数, n n n 是列数。我们访问每个原本为1的网格最多一次。
空间复杂度 O ( m × n ) O(m \times n) O(m×n),队列中最多会存放所有的土地,土地的数量最多为 m × n m \times n m×n 块,因此使用的空间为 O ( m × n ) O(m \times n) O(m×n)

  • 1
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
根据引用\[1\],可以使用暴力解法来求解滑动窗口的最大值。具体的做法是,遍历数组,对于每个窗口,使用一个内部循环来找到窗口中的最大值,并将其存储在结果数组中。时间复杂度为O(n*k),其中n为数组长度,k为窗口大小。 根据引用\[2\],还可以使用队列来求解滑动窗口的最大值。具体的做法是,使用一个双端队列来维护一个单调递减的窗口。遍历数组,对于每个元素,首先判断队头是否在滑动窗口范围内,如果不在,则将其从队头移除。然后,将当前元素与队尾元素比较,如果当前元素大于队尾元素,则将队尾元素移除,直到队列为空或者当前元素小于等于队尾元素。最后,将当前元素的索引插入队尾。如果滑动窗口的元素个数达到了k个,并且始终维持在窗口中,就将队头元素加入答案数组中。时间复杂度为O(n),其中n为数组长度。 综上所述,可以使用暴力解法或者使用队列来求解leetcode滑动窗口的最大值。 #### 引用[.reference_title] - *1* *3* [leetcode239. 滑动窗口最大值](https://blog.csdn.net/kkkkuuga/article/details/124829581)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^koosearch_v1,239^v3^insert_chatgpt"}} ] [.reference_item] - *2* [Leetcode#239. 滑动窗口最大值 (Java解法)](https://blog.csdn.net/paranior/article/details/114890555)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^koosearch_v1,239^v3^insert_chatgpt"}} ] [.reference_item] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值