1391. Check if There is a Valid Path in a Grid

问题:

给定一个n*m数组,代表公路。

  • 1:连接 left + right
  • 2:连接 up + down
  • 3:连接 left + down
  • 4:连接 right + down
  • 5:连接 left + up
  • 6:连接 right + up

求是否能够从左上角格子(0,0)到达,右下角(n-1,m-1)。

Example 1:
Input: grid = [[2,4,3],[6,5,2]]
Output: true
Explanation: As shown you can start at cell (0, 0) and visit all the cells of the grid to reach (m - 1, n - 1).

Example 2:
Input: grid = [[1,2,1],[1,2,1]]
Output: false
Explanation: As shown you the street at cell (0, 0) is not connected with any street of any other cell and you will get stuck at cell (0, 0)

Example 3:
Input: grid = [[1,1,2]]
Output: false
Explanation: You will get stuck at cell (0, 1) and you cannot reach cell (0, 2).

Example 4:
Input: grid = [[1,1,1,1,1,1,3]]
Output: true

Example 5:
Input: grid = [[2],[2],[2],[2],[2],[2],[6]]
Output: true
 

Constraints:
m == grid.length
n == grid[i].length
1 <= m, n <= 300
1 <= grid[i][j] <= 6

  

example 1:

example 2:

 

 

解法:BFS ,Union Find

解法一:BFS:

  • 状态:当前位置坐标。
    • visited也标记已访问过的坐标。
  • 选择:next=当前格子所连接的两个方向。
    • 除去:next:超出边界 or 已访问过位置 or 当前位置cur:不位于next的连接方向上。
      • op[cur].count(grid[next])==0

代码参考:

 1 class Solution {
 2 public:
 3     vector<vector<vector<int>>> dir = {{},{{0,-1},{0,1}},{{-1,0},{1,0}},{{0,-1},{1,0}},
 4                                {{1,0},{0,1}},{{0,-1},{-1,0}},{{-1,0},{0,1}}};
 5     vector<vector<unordered_set<int>>> opt = {{},{{1,4,6},{1,3,5}},{{2,3,4},{2,5,6}},
 6                                               {{1,4,6},{2,5,6}},{{2,5,6},{1,3,5}},
 7                                               {{1,4,6},{2,3,4}},{{2,3,4},{1,3,5}}};
 8     bool hasValidPath(vector<vector<int>>& grid) {
 9         int n = grid.size();
10         int m = grid[0].size();
11         queue<pair<int,int>> q;
12         unordered_set<int> visited;//i*300+j
13         q.push({0,0});
14         visited.insert(0);
15         while(!q.empty()) {
16             auto[i,j] = q.front();
17             q.pop();
18             if(i==n-1 && j==m-1) return true;
19             for(int k=0; k<2; k++) {//from & to
20                 auto d = dir[grid[i][j]][k];
21                 auto op = opt[grid[i][j]][k];
22                 int x = i+d[0];
23                 int y = j+d[1];
24                 //cout<<"x,y:"<<x<<","<<y<<endl;
25                 if(x<0 || y<0 || x>=n || y>=m || op.count(grid[x][y])==0) continue;
26                 if(visited.insert(x*300+y).second) {
27                     q.push({x,y});
28                     //cout<<"push:"<< grid[x][y]<<endl;
29                 }
30             }
31         }
32         return false;
33     }
34 };

 

解法二:Union Find

将每个cell的边+cell中心,都看作一个node,

那么每个街道的布局即可看作,将中心和其中两个边 代表的node 相连。

例如:

3:连接 left + down

  • 假设中心为(i,j)
  • left边为(i,j-1)
  • down边为(i+1,j)

布局3则可看作,将上述三个节点相连。

 

根据题意,对于节点(i,j)

按照上述方法进行标记节点的话,其节点坐标为(i*2,j*2)

那么对于(0,0) 中心节点坐标为(0,0)上边(-1,0)左边(0,-1)

整个地图的上边界和左边界都为-1,而我们只要求中心节点:起始(0,0)~终点((n-1)*2, (m-1)*2),也用不到-1的节点,因此不计算在内也完全可以。

 

使用union find方法,

那么共有2n*2m个节点。

构造记录root数组 uf[n][m]

初始化为各自坐标自己。

实现find,merge方法:

 1 class UnionFind {
 2 public:
 3     vector<vector<int>> uf;
 4     int m, n;
 5     UnionFind(int m1, int n1) {
 6         m=m1, n=n1;
 7         uf.resize(2*n, vector<int>(2*m));
 8         for(int i=0; i<2*n; i++) {
 9             for(int j=0; j<2*m; j++) {
10                 uf[i][j] = i*600+j;
11             }
12         }
13     }
14     int find(int i, int j) {
15         if(uf[i][j]!=(i*600+j)) {
16             uf[i][j] = find(uf[i][j]/600, uf[i][j]%600);
17         }
18         return uf[i][j];
19     }
20     void merge(int i, int j, int x, int y) {
21         if(x<0 || y<0 || x>=2*n || y>=2*m) return;
22         int ij = find(i,j);//Root(i,j)
23         int xy = find(x,y);//Root(x,y)
24         if(ij==xy) return;
25         uf[xy/600][xy%600] = ij;//connect two root:let uf(Root(x,y))==Root(i,j);
26         //cout<<"merge:uf["<<x<<"]["<<y<<"]:"<<ij<<endl;
27         return;
28     }
29 };

 

再利用union find进行对本问题的求解。

对每个cell,根据道路布局,进行节点merge

最后所求即是,起始节点和终点是否为同一个root。

代码参考:

 1 class Solution {
 2 public:
 3     vector<vector<int>> dir = {{-1,0},{1,0},{0,-1},{0,1}};//edges from center: up,down,left,right
 4     vector<unordered_set<int>> opt = {{2,5,6},{2,3,4},{1,3,5},{1,4,6}};
 5     bool hasValidPath(vector<vector<int>>& grid) {
 6         int n = grid.size();
 7         int m = grid[0].size();
 8         UnionFind node(m,n);
 9         for(int i=0; i<n; i++) {
10             for(int j=0; j<m; j++) {
11                 for(int k=0; k<4; k++) {
12                     if(opt[k].count(grid[i][j]))
13                         //connect: center + edge
14                         //center: 2*i, 2*j
15                         node.merge(2*i,2*j, 2*i+dir[k][0], 2*j+dir[k][1]); 
16                 }
17             }
18         }
19         return node.find(0,0) == node.find(2*n-2, 2*m-2);
20     }
21 };

 

posted @ 2021-03-21 11:46  habibah_chang  阅读(52)  评论(0编辑  收藏  举报