• 695. 岛屿的最大面积


    toc

    题目

    给定一个包含了一些 0 和 1 的非空二维数组 grid 。

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

    找到给定的二维数组中最大的岛屿面积。(如果没有岛屿,则返回面积为 0 。)

    示例 1:

    [[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:

    [[0,0,0,0,0,0,0,0]]
    对于上面这个给定的矩阵, 返回 0。

    注意: 给定的矩阵grid 的长度和宽度都不超过 50。

    来源:力扣(LeetCode)
    链接:https://leetcode-cn.com/problems/max-area-of-island
    著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

    解题思路

    本题需要找出聚集1的最大个数(上下左右相连)。可一条路走到黑式检测、选择上下左右任一个方向,检测是否是1,是1继续检测同方向,不是1则换方向继续一条路走到黑,直到检测不到1,此时统计完聚集1的个数。即深度优先搜索遍历

    代码

    class Solution {
    public:
        int DFS(const std::vector<std::vector<int>>& grid, int iXSize, int iYSize, 
                int x, int y, std::vector<std::vector<int>>& vecvecVisited){
            //边界检查
            if(x < 0 || x >= iXSize || y < 0 || y >= iYSize)
                return 0;        
            //当前坐标不是岛屿或已访问
            if(0 == grid[y][x] || 1 == vecvecVisited[y][x])
                return 0;
            //当前位置已访问标记
            vecvecVisited[y][x] = 1;
            //返回当前坐标的面积大小 及 上、下、左、右 位置面积
            return 1 + DFS(grid, iXSize, iYSize, x, y + 1, vecvecVisited) + DFS(grid, iXSize, iYSize, x, y - 1, vecvecVisited)
                 + DFS(grid, iXSize, iYSize, x - 1, y, vecvecVisited) + DFS(grid, iXSize, iYSize, x + 1, y, vecvecVisited);
        }
    
    
        int maxAreaOfIsland(vector<vector<int>>& grid) {
            int iMaxArea = 0;
            int iYSize = grid.size(), iXSize = grid.front().size();
            std::vector<std::vector<int>> vecvecVisited(50);
            for(auto & elem : vecvecVisited){
                elem.resize(50);
            }
    
            for(int y = 0; y < iYSize; y++){
                for(int x = 0; x < iXSize; x++){
                    iMaxArea = std::max(iMaxArea, DFS(grid, iXSize, iYSize, x, y, vecvecVisited));
                }
            }
            return iMaxArea;
        }
    };

    执行消耗内存分布图表更是惨不忍睹的仅超过6%,太惨就不贴图了...

    优化

    1. visited是二维的,二维的vector不同于二维的数组:
    • vector对象本身与其实际存储元素的空间是分开的,管理存储空间的vector对象本身也会占用内存空间。可降低vector对象个数来减少空间占用
    • 二维数组本质是一维数组语法糖,实际还是连续空间;但二维vector中,内层与外层vector的存储空间是真实独立的,这就意味着每次访问均会多一次寻址操作,对使用缓存也不友好。可将二维vector降维提高性能
    1. grid的大小是固定的,可将每次调用传入dfs函数的size,提为类成员,可减少传参个数、减少调用时拷贝的字节数,可以减少内存消耗(但测试后发现内存消耗并未减少,消耗的运行时间反倒增多,时间增多可以理解,因为需寻址this指针访问size成员,肯定没直接访问栈上的size快。但是内存消耗没减少就有点想不通了)

    代码

    class Solution {
    private:
        int m_iYSize = 0;
        int m_iXSize = 0;
    public:
        int DFS(const std::vector<std::vector<int>>& grid, int x, int y, std::vector<int>& visited){
            //边界检查
            if(x < 0 || x >= m_iXSize || y < 0 || y >= m_iYSize)
                return 0;        
            //当前坐标不是岛屿或已访问
            if(0 == grid[y][x] || 1 == visited[y * m_iXSize + x])
                return 0;
            //当前位置已访问标记
            visited[y * m_iXSize + x] = 1;
            //返回当前坐标的面积大小 及 上、下、左、右 位置面积
            return 1 + DFS(grid, x, y + 1, visited) + DFS(grid, x, y - 1, visited)
                 + DFS(grid, x - 1, y, visited) + DFS(grid, x + 1, y, visited);
        }
    
    
        int maxAreaOfIsland(vector<vector<int>>& grid) {
            int iMaxArea = 0;
            m_iYSize = grid.size(), m_iXSize = grid.front().size();
            std::vector<int> visited(2500, 0);
    
            for(int y = 0; y < m_iYSize; y++){
                for(int x = 0; x < m_iXSize; x++){
                    if(0 == grid[y][x])    //仅在grid中0多时有用
                        continue;
    
                    iMaxArea = std::max(iMaxArea, DFS(grid, x, y, visited));
                }
            }
            return iMaxArea;
        }
    };


    终于接近平均水平了,不过内存消耗依旧很惨。仅7%...

    优秀提交学习

    下图代码来自LeetCode中超越100%的提交代码

    不得不说,超越100%的代码真是挺新奇的,常规思路都是在函数入口判断边界,判断返回条件,导致了很多重复问的判断,图中的代码直接将判断交给了上层,由上层判断来避免额外的性能开销。
    哈哈,我也知道为什么我的内存消耗





    原创不易,转载请注明出处,谢谢
  • 相关阅读:
    作为一名JAVA程序员应该有怎样的就业思维
    Html +++++css总结
    spring知识点全部复习
    Spring注解问题,[action中注入service失败
    VMware中Ubuntu18配置静态IP地址
    MySQL5.7修改登录密码的几种方式
    MySQL忘记root密码
    Windows安装Redis
    Java两个整数相除保留n位小数
    Java四舍五入保留n位小数的常用写法
  • 原文地址:https://www.cnblogs.com/Keeping-Fit/p/14698253.html
Copyright © 2020-2023  润新知