934. Shortest Bridge

题解

题目是求两个连通块的最短路径,可以用宽搜。
宽搜有几个要注意的地方,1. 如何区分不同的连通块,2. 不要重复搜索。
在遍历的时候,首先找到第一个连通块,使用flood fill算法,把对应的连通块染色。然后再flood fill的同时,找到边缘的所有点,加入队列,之后在队列中,进行宽搜找到最短距离。
另外宽搜的时候,可以用距离数组维护是否需要加入队列中,不需要hash表。

代码

  • 由于是宽搜,距离数组更新的时候必然是第一次遍历的时候,因此不会重复遍历。

    1. class Solution {
    2. public:
    3. int n, m;
    4. int dx[4] = {0, 1, 0, -1};
    5. int dy[4] = {1, 0, -1, 0};
    6. typedef pair<int, int> PII;
    7. vector<vector<int>> dist;
    8. queue<PII> q;
    9. void flood_fill(vector<vector<int>>& grid, int x, int y) {
    10. grid[x][y] = -1;
    11. dist[x][y] = 0;
    12. q.push({x, y});
    13. for (int i = 0; i < 4; i ++) {
    14. int a = x + dx[i];
    15. int b = y + dy[i];
    16. if (a >= 0 && a < n && b >= 0 && b < m && grid[a][b] == 1) {
    17. flood_fill(grid, a, b);
    18. }
    19. }
    20. }
    21. int get_shortest_bridge(vector<vector<int>>& grid, int x, int y) {
    22. flood_fill(grid, x, y);
    23. while(q.size()) {
    24. int k = q.size();
    25. for (int i = 0; i < k; i ++) {
    26. auto p = q.front();
    27. q.pop();
    28. int x = p.first, y = p.second;
    29. // cout << x <<", " << y <<endl;
    30. for (int j = 0; j < 4; j ++) {
    31. int a = x + dx[j];
    32. int b = y + dy[j];
    33. // cout << "(" << a << ", " << b << ")" << endl;
    34. if (a >= 0 && a < n && b >= 0 && b < m && dist[a][b] > dist[x][y] + 1) {
    35. dist[a][b] = dist[x][y] + 1;
    36. q.push({a, b});
    37. }
    38. if (a >= 0 && a < n && b >= 0 && b < m && grid[a][b] == 1) {
    39. return dist[a][b] - 1;
    40. }
    41. }
    42. }
    43. }
    44. return -1;
    45. }
    46. int shortestBridge(vector<vector<int>>& grid) {
    47. n = grid.size(), m = grid[0].size();
    48. dist = vector<vector<int>>(n, vector<int>(m, 1e8));
    49. for(int i = 0; i < n; i ++) {
    50. for (int j = 0; j < m; j ++) {
    51. if (grid[i][j] == 1) {
    52. return get_shortest_bridge(grid, i, j);
    53. }
    54. }
    55. }
    56. return -1;
    57. }
    58. };