算法入门——广度优先搜索 / 深度优先搜索(三)

01 矩阵

广度优先搜索

思路:

  • 对于 「Tree 的 BFS」 (典型的「单源 BFS」):
    • 首先把 root 节点入队,再一层一层无脑遍历就行了
  • 对于 「图 的 BFS」 (「多源 BFS」)
    • 同样将源节点入队,再取出遍历
    • 与 「Tree 的 BFS」的区别注意:
      • Tree 只有 1 个 root,而图可以有多个源点,所以首先需要把多个源点都入队
      • Tree 是有向的因此不需要标识是否访问过,而对于无向图来说,必须得标志是否访问过!为了防止某个节点多次入队
  • 做法:

    • 遍历数组

      • 将源点0入队
      • 将1的赋值为 -1
        • 未被访问的节点
    • 遍历队列

      • 对该源点的上下左右一一进行判断
        • 不能越界、等于-1:为被访问
        • 将其值改为源点值 + 1
        • 这个被访问的 -1 节点 入队(防止其四周有未访问的-1节点,并且源点0是服务访问到的),确保节点都被访问
    • 队列空了:都访问了,处理结束

    • class Solution {
          public int[][] updateMatrix(int[][] matrix) {
              // 首先将所有的 0 都入队,并且将 1 的位置设置成 -1,表示该位置是 未被访问过的 1
              Queue<int[]> queue = new LinkedList<>();
              int m = matrix.length, n = matrix[0].length;
              for (int i = 0; i < m; i++) {
                  for (int j = 0; j < n; j++) {
                      if (matrix[i][j] == 0) {
                          queue.offer(new int[] {i, j});
                      } else {
                          matrix[i][j] = -1;
                      } 
                  }
              }
              
              int[] dx = new int[] {-1, 1, 0, 0};
              int[] dy = new int[] {0, 0, -1, 1};
              while (!queue.isEmpty()) {
                  int[] point = queue.poll();
                  int x = point[0], y = point[1];
                  for (int i = 0; i < 4; i++) {
                      int newX = x + dx[i];
                      int newY = y + dy[i];
                      // 如果四邻域的点是 -1,表示这个点是未被访问过的 1
                      // 所以这个点到 0 的距离就可以更新成 matrix[x][y] + 1。
                      if (newX >= 0 && newX < m && newY >= 0 && newY < n 
                              && matrix[newX][newY] == -1) {
                          matrix[newX][newY] = matrix[x][y] + 1;
                          queue.offer(new int[] {newX, newY});
                      }
                  }
              }
      
              return matrix;
          }
      }
      

好文:2种BFS,详解DP, 🤷♀️必须秒懂! - 01 矩阵 - 力扣(LeetCode) (leetcode-cn.com)

二、腐烂的橘子

  • 相比上面,思路差不多,但略简单

思路

  • 是图的遍历
  • 采用广度优先搜索
  • 每个源点标记就是 1、2这样的值
    • 1:等待被污染的新鲜橘子
    • 2:已经腐败的橘子:只访问一次,不重复访问的条件

做法

  • 遍历数组
    • 统计新鲜橘子数量
    • 将腐败橘子入队
  • 记录初始腐败橘子数量
  • 遍历队列
    • 每次出一个源节点
    • 将其四个正方向的位置
      • 是新鲜橘子:赋值为2并污染、count减一、入队
    • size减一:属于该批的橘子数量减一
    • 当size 等于 0:
      • 这一批的腐败橘子已访问完
      • 若队列中还有节点:说明这一批腐败橘子有污染到新鲜橘子,则时间增加
      • size更新:下次不同批次进行污染
  • 最后count不等于0:存在没被污染的新鲜橘子:返回-1
  • 不然返回time:也可称之为污染环数
class Solution {
   public int orangesRotting(int[][] grid) {
       //将所有的腐烂橘子入队
       //值为2入队,统计新鲜橘子数量
       Queue<int[]> queue = new LinkedList<>();
       int n = grid.length;
       int m = grid[0].length;
       int count = 0;
       for(int i = 0; i < n; i++) {
           for(int j = 0; j < m; j++) {
               if(grid[i][j] == 2) {
                   queue.offer(new int[] {i, j});
               } else if(grid[i][j] == 1) {
                   ++count;
               }
           }
       }

       //上、下、左、右四个附近节点
       int[] dx = new int[] {-1, 1, 0, 0};
       int[] dy = new int[] {0, 0, -1, 1};
       //统计污染时间
       int time = 0;
       //统计不同腐败批次的橘子数量
       int size = queue.size();
       while(!queue.isEmpty()) {
           //处理橘子,附近的1赋值为2且入队
           int[] point = queue.poll();
           int x = point[0], y = point[1];
           for(int i = 0; i < 4; i++) {
               int newx = x + dx[i];
               int newy = y + dy[i];
               if(newx >= 0 && newx < n && newy >= 0 && newy < m
                   && grid[newx][newy] == 1) {
                       //不越界(4个正方向之一)、是新鲜的橘子
                       grid[newx][newy] = 2;
                       --count;
                       queue.offer(new int[] {newx, newy});
               }
           }
           //处理时间,橘子腐败是一批开始的,不同批次占据不同的时间段,初始的坏橘子占据第一个分钟
           //初始橘子污染的橘子(第二批):占据第二个分钟....依次类推
           //每批次有污染新鲜橘子:队列不为空,时间加1
           size--;
           if(size == 0) {
               if(queue.size() > 0) {
                   time++;
               }
               size = queue.size();
           }
       }
       if(count > 0) {
           return -1;
       }
       return time;
   }
}  
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 212,884评论 6 492
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,755评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 158,369评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,799评论 1 285
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,910评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,096评论 1 291
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,159评论 3 411
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,917评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,360评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,673评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,814评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,509评论 4 334
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,156评论 3 317
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,882评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,123评论 1 267
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,641评论 2 362
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,728评论 2 351

推荐阅读更多精彩内容