【LeetCode】员工的重要性 | 图像渲染 | 岛屿问题

简介: 【LeetCode】员工的重要性 | 图像渲染 | 岛屿问题

👉员工的重要性👈


给定一个保存员工信息的数据结构,它包含了员工 唯一的 id ,重要度 和 直系下属的 id 。比如,员工 1 是员工 2 的领导,员工 2 是员工 3 的领导。他们相应的重要度为 15 , 10 , 5 。那么员工 1 的数据结构是 [1, 15, [2]] ,员工 2的数据结构是 [2, 10, [3]] ,员工 3 的数据结构是 [3, 5, []] 。注意虽然员工 3 也是员工 1 的一个下属,但是由于并不是直系下属,因此没有体现在员工 1 的数据结构中。


现在输入一个公司的所有员工信息,以及单个员工 id ,返回这个员工和他所有下属的重要度之和。

bf2e3ead758445e0a056a6e143de115d.png


思路:员工和领导的关心可以抽象成一块多叉树,想要求出一个员工和他所有下属的重要度之和,可以将该员工看做根节点,然后递归去求其所有子树的重要性之和,就能够得到总的重要性了。

084eb9c5dcc7410197fc7679076e92fb.png


/*
// Definition for Employee.
class Employee {
public:
    int id;
    int importance;
    vector<int> subordinates;
};
*/
class Solution 
{
private:
    int DFS(unordered_map<int, Employee*>& info, int id)
    {
        int ret = info[id]->importance; // 自己的重要性
        for(auto& id : info[id]->subordinates)
        {
            // 递归去求所有下属的重要性
            ret += DFS(info, id);  
        }
        return ret;
    }
public:
    int getImportance(vector<Employee*> employees, int id) 
    {
        // 使用哈希表来建立id和节点指针的关系
        // 有了节点指针就能够找到其所有直系下属的id
        unordered_map<int, Employee*> info;
        for(auto& e : employees)
        {
            info[e->id] = e;
        }
        return DFS(info, id);
    }
};

7e66d392fcb841b79b911d44b091e64c.png

👉图像渲染👈

9674e2bb8b5b402c9fde0b184dd825be.png


思路:本道题的意思是给定一个起点 (sr, sc) 和 新颜色 newColor,记该起点的颜色为 oldColor,将起点和其上向左右为 oldColor 的点的颜色都改为 newColor。借助递归就能够修改上下左右的颜色了,重要的是判断上下左右是否越界。


class Solution 
{
private:
    // 向上下左右移动一格
    int nextPosition[4][2] = {{-1, 0}, {1, 0}, {0, -1}, {0, 1}};
    void DFS(vector<vector<int>>& image, vector<vector<bool>>& mark, int X, int Y, int oldColor, int newColor)
    {
        // 修改当前格子的颜色,并标记为true
        image[X][Y] = newColor;
        mark[X][Y] = true;
        for(int i = 0; i < 4; ++i)
        {
            int newX = X + nextPosition[i][0];
            int newY = Y + nextPosition[i][1];
            // 判断是否越界
            if(newX >= image.size() || newX < 0
            || newY >= image[0].size() || newY < 0)
                continue;
            // 如果当前格子颜色为oldColor且没有被标记成true
            // 就递归去修改颜色
            if(image[newX][newY] == oldColor && mark[newX][newY] == false)
                DFS(image, mark, newX, newY, oldColor, newColor);
        }
    }
public:
    vector<vector<int>> floodFill(vector<vector<int>>& image, int sr, int sc, int color) 
    {
        int m = image.size();
        int n = image[0].size();
        vector<vector<bool>> mark(m, vector<bool>(n, false));
        DFS(image, mark, sr, sc, image[sr][sc], color);
        return image;
    }
};

7c20423610ba4743adf847606ce11cf1.png


👉被环绕的区域👈


给你一个 m x n 的矩阵 board ,由若干字符 ‘X’ 和 ‘O’ ,找到所有被 ‘X’ 围绕的区域,并将这些区域里所有的 ‘O’ 用 ‘X’ 填充。

f95ca203d2424a088b4fbdc9e68b2630.png


思路:通过上图可以发现,如果 ‘O’ 没有被 ‘X’ 环绕了,那么这个 ‘O’ 肯定是在矩阵的四条边上的任意一条。那么,我们可以检查四条边上的点的字符是不是 ‘O’,如果是 ‘O’,我们就将其标记成 ‘A’,说明该字符 ‘O’ 不被 ‘X’ 环绕,然后递归去查找与该点连通的 ‘O’,也将它们改成 ‘A’。那么检查完四条边上的点后,没有被 ‘X’ 环绕的 ‘O’ 都被改成为 ‘A’,需要将它们改回 ‘O’;而被 ‘X’ 环绕的 ‘O’ 还是 ‘O’,需要将它们改成 ‘X’。


class Solution 
{
private:
    int nextPosition[4][2] = {{-1, 0}, {1, 0}, {0, -1}, {0, 1}};
    void DFS(vector<vector<char>>& board,int X, int Y)
    {
        // 标记此位置的'O'和边上是联通的
        board[X][Y] = 'A';
        // 查找四个方向是否有连通的'O'
        for(int i = 0; i < 4; ++i)
        {
            int newX = X + nextPosition[i][0];
            int newY = Y + nextPosition[i][1];
            // 越界
            if(newX >= board.size() || newX < 0
            || newY >= board[0].size() || newY < 0)
                continue;
            // 递归去查找连通的'O'
            if(board[newX][newY] == 'O')
                DFS(board, newX, newY);
        }
    }
public:
    void solve(vector<vector<char>>& board) 
    {
        int row = board.size();
        int col = board[0].size();
        for(int j = 0; j < col; ++j)
        {
            if(board[0][j] == 'O')
                DFS(board, 0, j);
            if(board[row - 1][j] == 'O')
                DFS(board, row - 1, j);
        }
        for(int i = 1; i < row - 1; ++i)
        {
            if(board[i][0] == 'O')
                DFS(board, i, 0);
            if(board[i][col - 1] == 'O')
                DFS(board, i, col - 1);
        }
        for(int i = 0; i < row; ++i)
        {
            for(int j = 0; j < col; ++j)
            {
                if(board[i][j] == 'A')
                    board[i][j] = 'O';
                else if(board[i][j] == 'O')
                    board[i][j] = 'X';
            }
        }
    }
};

6ac90df4b3cb47a9a263a6accee69243.png

👉岛屿的周长👈


给定一个 row x col 的二维网格地图 grid ,其中:grid[i][j] = 1 表示陆地, grid[i][j] = 0 表示水域。


网格中的格子 水平和垂直方向相连(对角线方向不相连)。整个网格被水完全包围,但其中恰好有一个岛屿(或者说,一个或多个表示陆地的格子相连组成的岛屿)。


岛屿中没有“湖”(“湖” 指水域在岛屿内部且不和岛屿周围的水相连)。格子是边长为 1 的正方形。网格为长方形,且宽度和高度均不超过 100。计算这个岛屿的周长。

1ccba9f7061240f08d6fe08f278a7f47.png

思路:对于一个陆地格子的每条边,它被算作岛屿的周长当且仅当这条边为网格的边界或者相邻的另一个格子为水域。 因此,我们可以遍历每个陆地格子,看其四个方向是否为边界或者水域,如果是,将这条边的贡献(即 1)加入答案 ret 即可。


深度优先搜索


class Solution 
{
private:
    int nextPosition[4][2] = {{-1, 0}, {1, 0}, {0, -1}, {0, 1}};
    int DFS(vector<vector<int>>& grid, int X, int Y)
    {
        grid[X][Y] = 2; // 将格子的数改成2,表示该格子的边数已经加过了
        int ret = 0;
        for(int i = 0; i < 4; ++i)
        {
            int newX = X + nextPosition[i][0];
            int newY = Y + nextPosition[i][1];
            // 越界或者上下左右方向是水域,则边数加一
            if(newX < 0 || newX >= grid.size()
            || newY < 0 || newY >= grid[0].size()
            || grid[newX][newY] == 0)
            {
                ret += 1;
                continue;
            }
            else if(grid[newX][newY] == 1)  // 递归求该格子的边数
                ret += DFS(grid, newX, newY);
        }
        return ret;
    }
public:
    int islandPerimeter(vector<vector<int>>& grid) 
    {
        int row = grid.size();
        int col = grid[0].size();
        int ret = 0;
        for(int i = 0; i < row; ++i)
        {
            for(int j = 0; j < col; ++j)
            {
                if(grid[i][j] == 1)
                    ret += DFS(grid, i, j);
            }
        }
        return ret;
    }
};


20e5607d40444127ad3f303a343f3d35.png


迭代


class Solution 
{
private:
    int nextPosition[4][2] = {{-1, 0}, {1, 0}, {0, -1}, {0, 1}};
public:
    int islandPerimeter(vector<vector<int>>& grid) 
    {
        int row = grid.size();
        int col = grid[0].size();
        int ret = 0;
        for(int i = 0; i < row; ++i)
        {
            for(int j = 0; j < col; ++j)
            {
                if(grid[i][j] == 1)
                {
                    int count = 0;
                    // 查看该格子的四个方向是不是越界或者水域
                    // 如果是,格子的边数count加一
                    for(int k = 0; k < 4; ++k)
                    {
                        int newI = i + nextPosition[k][0];
                        int newJ = j + nextPosition[k][1];
                        if(newI < 0 || newI >= row
                        || newJ < 0 || newJ >= col
                        || grid[newI][newJ] == 0)
                            ++count;
                    }
                    ret += count;   // 将该格子的边数加到总边数去
                }
            }
        }
        return ret;
    }
};

139f98e97c5646eaabc82bc10402e6ab.png


👉岛屿的数量👈


给你一个由 ‘1’(陆地)和 ‘0’(水)组成的的二维网格,

请你计算网格中岛屿的数量。


岛屿总是被水包围,并且每座岛屿只能由水平方向和/或竖直方向上相邻的陆地连接形成。


此外,你可以假设该网格的四条边均被水包围。


思路:本题的意思是连在一起的陆地都算做一个岛屿,本题可以采用类似渲染的做法,尝试以每个点作为渲染的起点,可以渲染的陆地都算做一个岛屿,最后看渲染了多少次,即深度优先算法执行了多少次。


class Solution 
{
private:
    int nextPosition[4][2] = {{-1, 0}, {1, 0}, {0, -1}, {0, 1}};
    void DFS(vector<vector<char>>& grid, int X, int Y)
    {
        grid[X][Y] = '2';   // 标记该位置已经查找过了
        for(int i = 0; i < 4; ++i)
        {
            int newX = X + nextPosition[i][0];
            int newY = Y + nextPosition[i][1];
            // 越界
            if(newX < 0 || newX >= grid.size()
            || newY < 0 || newY >= grid[0].size())
                continue;
            // 递归去查找
            if(grid[newX][newY] == '1')
                DFS(grid, newX, newY);
        }
    }
public:
    int numIslands(vector<vector<char>>& grid) 
    {
        int row = grid.size();
        int col = grid[0].size();
        int ret = 0;
        for(int i = 0; i < row; ++i)
        {
            for(int j = 0; j < col; ++j)
            {
                if(grid[i][j] == '1')
                {
                    ++ret;
                    DFS(grid, i, j);
                }
            }
        }
        return ret;
    }
};

88d6a07c80734eda9e32d583be629982.png


👉岛屿的最大面积👈


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

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


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


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


思路:本道题也是类似的,最多相邻 1 的个数就是岛屿的最大面积。


class Solution 
{
private:
    int nextPosition[4][2] = {{-1, 0}, {1, 0}, {0, -1}, {0, 1}};
    int DFS(vector<vector<int>>& grid, int X, int Y)
    {
        grid[X][Y] = 2; // 做标记,表明这块土地已经被查找过了
        int ret = 1;    // 进来就说明至少有一块土地了
        for(int i = 0; i < 4; ++i)
        {
            int newX = X + nextPosition[i][0];
            int newY = Y + nextPosition[i][1];
            if(newX < 0 || newX >= grid.size()
            || newY < 0 || newY >= grid[0].size()
            || grid[newX][newY] == 0)
                continue;
            // 递归去查找相邻的土地
            if(grid[newX][newY] == 1)
                ret += DFS(grid, newX, newY);
        }
        return ret;
    }
public:
    int maxAreaOfIsland(vector<vector<int>>& grid) 
    {
        int row = grid.size();
        int col = grid[0].size();
        int Max = 0;
        for(int i = 0; i < row; ++i)
        {
            for(int j = 0; j < col; ++j)
            {
                if(grid[i][j] == 1)
                {
                    int ret = DFS(grid, i, j);
                    Max = ret > Max ? ret : Max;
                }
            }
        }
        return Max;
    }
};

df03e736f2644046a912216ef7977a7d.png


👉总结👈


本篇讲解了几道 OJ 题,分别是员工的重要性、图像渲染和岛屿问题等。那么以上就是本篇博客的全部内容了,如果大家觉得有收获的话,可以点个三连支持一下!谢谢大家!💖💝❣️





相关文章
|
1月前
|
机器学习/深度学习
Leetcode第48题(旋转图像)
这篇文章介绍了LeetCode第48题“旋转图像”的解题方法,通过原地修改二维矩阵实现图像的顺时针旋转90度。
27 0
Leetcode第48题(旋转图像)
|
3月前
|
存储 算法
LeetCode第48题旋转图像
LeetCode第48题"旋转图像"的解题方法,通过两次翻转操作——先水平翻转再对角线翻转,实现了原地旋转矩阵的效果。
LeetCode第48题旋转图像
|
5月前
|
存储 机器学习/深度学习 算法
python 五种算法转置后翻转、层次旋转、递归分块、一次性旋转、环状替换 实现旋转图像【力扣题48】
python 五种算法转置后翻转、层次旋转、递归分块、一次性旋转、环状替换 实现旋转图像【力扣题48】
|
5月前
|
SQL 存储 移动开发
力扣第185题:部门工资前三高的员工
力扣第185题:部门工资前三高的员工
|
5月前
|
SQL 算法 大数据
深入解析力扣184题:部门工资最高的员工(子查询与窗口函数详解)
深入解析力扣184题:部门工资最高的员工(子查询与窗口函数详解)
|
5月前
|
机器学习/深度学习 存储
力扣经典150题第三十六题:旋转图像
力扣经典150题第三十六题:旋转图像
32 0
|
5月前
|
算法
【经典LeetCode算法题目专栏分类】【第9期】深度优先搜索DFS与并查集:括号生成、岛屿问题、扫雷游戏
【经典LeetCode算法题目专栏分类】【第9期】深度优先搜索DFS与并查集:括号生成、岛屿问题、扫雷游戏
|
5月前
|
SQL 算法 大数据
深入解析力扣181题:超过经理收入的员工(自连接方法详解及模拟面试问答)
深入解析力扣181题:超过经理收入的员工(自连接方法详解及模拟面试问答)
|
6月前
|
机器学习/深度学习
leetcode代码记录(旋转图像
leetcode代码记录(旋转图像
41 0
|
6月前
|
算法 定位技术
【leetcode】剑指 Offer II 105. 岛屿的最大面积-【深度优先DFS】
【leetcode】剑指 Offer II 105. 岛屿的最大面积-【深度优先DFS】
72 0