• 算法学习 | 深度优先搜索~一条道走到黑


    目录

    员工的重要性

    图像渲染 

    岛屿的周长 

    被围绕的区域

    岛屿数量 


     

    深度优先搜索(Depth First Search):深度优先搜索属于图算法的一种,其过程主要是对每一个可能的分支路径深入到不能再深入到为止,而且每个节点只能访问一次。深度优先搜索本质上就是暴力搜索,遍历了所有可能的情况,必然能得到解。DFS搜索的流程是一个树的形式,每次一条路走到黑。

    深度优先搜索的关键是解决“当下该如何做”,下一步的做法和当下的做法是一致的。“当下如何做”一般是尝试每一种可能,用for循环遍历对于每一种可能确定之后,继续走下一步,当前的剩余可能等到从下一步回退之后再处理。据此可以抽象出深度优先搜索的模型

    1. dfs(当前这一步的处理逻辑) {
    2. 1.判断边界,是否已经一条道走到黑:回退
    3. 2.尝试当下的每一种可能
    4. 3.确定一种可能之后,继续下一步dfs(下一步)
    5. }

    员工的重要性

    题目链接:leetcode-690.员工的重要性

    示例

    输入:[[1, 5, [2, 3]], [2, 3, []], [3, 3, []]], 1

    输出:11

    描述:员工1自身的重要度是 5,他有两个直系下属 2 和 3 ,而且 2 和 3 的重要度均为 3 。因此员工 1 的总重要度是 5 + 3 + 3 = 11 。

    题目分析

    根据题意,可以根据给定的员工id找到员工,从该员工开始遍历,对于每个员工,将其重要性相加,然后再对该员工的每个下属进行遍历,直到所有下属遍历完毕,此时的总和就是给定id的员工及他所有下属的重要度之和。由于每个员工的编号都不同,可以使用哈希表存储员工编号和对应员工,通过员工编号可以找到对应员工

    1. class Solution {
    2. public int getImportance(List employees, int id) {
    3. if (employees.isEmpty()) {
    4. return 0;
    5. }
    6. Map info = new HashMap<>();
    7. for (Employee e : employees) {
    8. info.put(e.id, e);
    9. }
    10. return dfs(info, id);
    11. }
    12. private int dfs(Map info, int id) {
    13. Employee curE = info.get(id);
    14. int sumE = curE.importance;
    15. for (int curId : curE.subordinates) {
    16. sumE += dfs(info, curId);
    17. }
    18. return sumE;
    19. }
    20. }

    图像渲染 

    题目链接:leetcode-773.图像渲染

     

    示例 

    输入:image = [[1,1,1],[1,1,0],[1,0,1]],sr = 1, sc = 1, newColor = 2

    输出:[[2,2,2],[2,2,0],[2,0,1]]

     

    题目分析: 

    本题的意思是给定一个二维数组表示的图画,并给定一个初始位置和修改后的颜色数字,从初始位置开始,遍历它的上下左右,如果值与初始位置的值相等,就进行修改,一直到遍历完所有符合条件的结点为止.

    1. class Solution {
    2. int[][] nextPosition = {{1, 0}, {-1, 0}, {0, 1}, {0, -1}};
    3. public int[][] floodFill(int[][] image, int sr, int sc, int color) {
    4. if (image == null || image.length == 0) {
    5. return new int[0][0];
    6. }
    7. int flag = image[sr][sc];
    8. if (flag != color) {
    9. dfs(image, sr, sc, color, flag);
    10. }
    11. // dfs(image, sr, sc, color, flag);
    12. return image;
    13. }
    14. private void dfs(int[][] image, int sr, int sc, int color, int flag) {
    15. if (image[sr][sc] == flag) {
    16. image[sr][sc] = color;
    17. for (int i = 0; i < 4; i++) {
    18. int newSr = sr + nextPosition[i][0];
    19. int newSc = sc + nextPosition[i][1];
    20. if (newSr >= 0 && newSr < image.length && newSc >= 0 && newSc < image[0].length) {
    21. dfs(image, newSr, newSc, color, flag);
    22. }
    23. }
    24. }
    25. }
    26. }

    岛屿的周长 

    题目链接:leetcode-463.岛屿的周长

    示例 

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

    输出:16

    题目分析

    根据题意,每次遍历到陆地时,先判断其是否处于边界,如果处于上下左右四个边界,则周长+1,如果不处于边界,就判断其上下左右是否为海洋,如果为海洋,则周长+1,如果为陆地,则不进行操作,每遍历一个陆地后,将其标记出来,下次如果又到了这块陆地,就返回。

    1. class Solution {
    2. int[][] nextPosition = { {1, 0}, {-1, 0}, {0, 1}, {0, -1} };
    3. int ret;
    4. public int islandPerimeter(int[][] grid) {
    5. if (grid == null || grid.length == 0) {
    6. return 0;
    7. }
    8. int m = grid.length;
    9. int n = grid[0].length;
    10. int[][] book = new int[m][n];
    11. for (int i = 0; i < grid.length; i++) {
    12. for (int j = 0; j < grid[0].length; j++) {
    13. if (grid[i][j] == 1) {
    14. dfs(grid, book, i, j, m, n);
    15. break;
    16. }
    17. }
    18. }
    19. return ret;
    20. }
    21. private void dfs(int[][] grid, int[][] book, int row, int col, int m, int n) {
    22. if (row < 0 || row >= m || col < 0 || col >= n || grid[row][col] == 0) {
    23. ret++;
    24. return ;
    25. }
    26. if (book[row][col] == 1) {
    27. return ;
    28. }
    29. book[row][col] = 1;
    30. for (int i = 0; i < 4; i++) {
    31. int newRow = row + nextPosition[i][0];
    32. int newCol = col + nextPosition[i][1];
    33. dfs(grid, book, newRow, newCol, m, n);
    34. }
    35. }
    36. }

    被围绕的区域

    题目链接leetcode-130.被围绕的区域

     

    例如

    输入:board = [["X","X","X","X"],["X","O","O","X"],["X","X","O","X"],["X","O","X","X"]]

    输出:[["X","X","X","X"],["X","X","X","X"],["X","X","X","X"],["X","O","X","X"]]

    题目分析

     由题意分析可知,只要其他的O与边界上的O相连,就不能被更换,因此,从四个边界的O符号开始,每次判断它的上下左右,只要与边界相连,就将其暂时设为*,接下来从这个*开始,继续寻找它的上下左右,直至到边界值为止,这里的边界值即超越矩阵范围或者遇到X为止.

    注意

    1. if (board[x][y] == '*') {
    2. return ;
    3. }

    该判断语句一定要加上,否则当遇到*时,就会一直陷入死循环

    1. class Solution {
    2. public void solve(char[][] board) {
    3. if (board == null || board.length == 0) {
    4. return ;
    5. }
    6. int m = board.length;
    7. int n = board[0].length;
    8. for (int i = 0; i < m; i++) {
    9. if (board[i][0] == 'O') {
    10. dfs(board, i, 0);
    11. }
    12. if (board[i][n - 1] == 'O') {
    13. dfs(board, i, n - 1);
    14. }
    15. }
    16. for (int i = 1; i < n - 1; i++) {
    17. if (board[0][i] == 'O') {
    18. dfs(board, 0, i);
    19. }
    20. if (board[m - 1][i] == 'O') {
    21. dfs(board, m - 1, i);
    22. }
    23. }
    24. for (int i = 0; i < m; i++) {
    25. for (int j = 0; j < n; j++) {
    26. if (board[i][j] == 'O') {
    27. board[i][j] = 'X';
    28. }
    29. if (board[i][j] == '*') {
    30. board[i][j] = 'O';
    31. }
    32. }
    33. }
    34. }
    35. private void dfs(char[][] board, int x, int y) {
    36. if (x < 0 || y < 0 || x >= board.length || y >= board[0].length || board[x][y] == 'X') {
    37. return ;
    38. }
    39. if (board[x][y] == '*') {
    40. return ;
    41. }
    42. board[x][y] = '*';
    43. dfs(board, x + 1, y);
    44. dfs(board, x - 1, y);
    45. dfs(board, x, y + 1);
    46. dfs(board, x, y - 1);
    47. }
    48. }

    岛屿数量 

    题目链接:leetcode-200.岛屿数量

     

    例如

    输入:grid = [
      ["1","1","1","1","0"],
      ["1","1","0","1","0"],
      ["1","1","0","0","0"],
      ["0","0","0","0","0"]
    ]

    输出: 1

    题目分析

    对于该题,从任意一个陆地出发,一直遍历它的上下左右,直至四周都是边界或海洋为止,对于每个遍历到过的陆地都将其标记出来,遍历整个二维数组,将每一个未标记过的陆地都作为起点遍历一遍。每次结束之后岛屿数量+1,直至所有陆地都被标记过后为止

    代码

    1. class Solution {
    2. public int numIslands(char[][] grid) {
    3. if (grid == null || grid[0].length == 0) {
    4. return 0;
    5. }
    6. int m = grid.length;
    7. int n = grid[0].length;
    8. int[][] book = new int[m][n];
    9. int ret = 0;
    10. for (int i = 0; i < m; i++) {
    11. for (int j = 0; j < n; j++) {
    12. if (grid[i][j] == '1' && book[i][j] == 0) {
    13. dfs(grid, book, i, j);
    14. ret++;
    15. }
    16. }
    17. }
    18. return ret;
    19. }
    20. private void dfs(char[][] grid, int[][] book, int x, int y) {
    21. if (x < 0 || y < 0 || x >= grid.length || y >= grid[0].length || grid[x][y] == '0') {
    22. return ;
    23. }
    24. if (book[x][y] == 1) {
    25. return ;
    26. }
    27. book[x][y] = 1;
    28. dfs(grid, book, x + 1, y);
    29. dfs(grid, book, x - 1, y);
    30. dfs(grid, book, x, y + 1);
    31. dfs(grid, book, x, y - 1);
    32. }
    33. }

     

     

     

  • 相关阅读:
    【STM32】标准库-自定义BootLoader
    vs+qt项目gitlab-ci 配置
    golang——接口
    Go快速上手之基础语法 | 青训营笔记
    docker-swarm集群管理命令
    Django笔记十六之aggregate聚合操作
    你想知道的do{...}while(0)的作用,都在这里了
    【VMware vSphere】搭建属于自己的 vSphere 实验环境(3)——Windows 系统安装与服务部署
    EM@坐标@函数@图象的对称和翻折变换
    【FPGA帧差】基于VmodCAM摄像头的帧差法目标跟踪FPGA实现
  • 原文地址:https://blog.csdn.net/qq_58284486/article/details/128035006