Leetcode每日一题 —— 1391. 检查网格中是否存在有效路径

2026-04-29 08:552阅读0评论SEO资讯
  • 内容介绍
  • 文章标签
  • 相关推荐
问题描述:
力扣 LeetCode

1391. 检查网格中是否存在有效路径 - 力扣(LeetCode)

1391. 检查网格中是否存在有效路径 - 给你一个 m x n 的网格 grid。网格里的每个单元都代表一条街道。grid[i][j] 的街道可以是: * 1 表示连接左单元格和右单元格的街道。 * 2 表示连接上单元格和下单元格的街道。 * 3表示连接左单元格和下单元格的街道。 * 4 表示连接右单元格和下单元格的街道。 * 5 表示连接左单元格和上单元格的街道。 * 6...


思路

大体上其实和昨天的思路比较相近,同样可以用并查集,扫描网格时也同样可以从上至下、从左至右扫描,对于每个格子都尝试往下或者往右走以进行合并。

和之前题不同的地方就在于,这题限制了每个格子处的行进方向

咱的做法是建立了一个硬编码的 patterns 表来表示向右或者向下走时,某个编号的街道是否能走向另一个编号的街道。这样能防止代码写得太复杂。


代码

class Solution { public: bool hasValidPath(vector<vector<int>>& grid) { // 这题还挺有意思,其实就是限定了每个格子处的行进方向 // 依旧可以并查集解决 int m=grid.size(),n=grid[0].size(); int ufLen=m*n; vector<int> parents(ufLen,-1),sizes(ufLen,1); auto find=[&](auto&& self, int x) -> int { return parents[x]==-1 ? x : parents[x]=self(self,parents[x]); }; auto merge=[&](int x1,int x2) -> void { int root1=find(find,x1),root2=find(find,x2); if(root1==root2){ // 已经合并 return; } // 小树并入大树 if(sizes[root1]<sizes[root2]){ swap(root1,root2); } parents[root2]=root1; sizes[root1]+=sizes[root2]; }; // 扫描网格,依旧看每个格子向下或者向右能不能走 int drcts[][2]={ {0,1}, {1,0}, }; // patterns[i][j][k] // i 表示尝试行进方向(右 i=0, 下 i=1) // j+1 表示当前格子的街道编号 // k+1 表示行进后的街道编号 // 如果 patterns[i][j][k]=true 就说明能走 bool patterns[2][6][6]={ { {true,false,true,false,true,false}, {false,false,false,false,false,false}, // 街道 2 无法往右走 {false,false,false,false,false,false}, {true,false,true,false,true,false}, {false,false,false,false,false,false}, {true,false,true,false,true,false}, }, { {false,false,false,false,false,false}, // 街道 1 无法往下走 {false,true,false,false,true,true}, {false,true,false,false,true,true}, {false,true,false,false,true,true}, {false,false,false,false,false,false}, {false,false,false,false,false,false}, }, }; for(int i=0;i<m;i++){ for(int j=0;j<n;j++){ for(int k=0;k<2;k++){ int nextI=i+drcts[k][0],nextJ=j+drcts[k][1]; // 没有越界的话就判断能不能往这个方向走,如果可以就合并 if(nextI>=m||nextJ>=n||!patterns[k][grid[i][j]-1][grid[nextI][nextJ]-1]){ continue; } merge(i*n+j,nextI*n+nextJ); } } } // 最后判断首个和最后一个是否连通 return find(find,0) == find(find, ufLen-1); } }; 网友解答:


--【壹】--:

type Street = Int neighbor :: (Int, Int) -> Int -> Street -> [Int] neighbor (m, n) x street = let (r, c) = x `divMod` n candidates = case street of 1 -> [(r, c + 1), (r, c - 1)] -- LR 2 -> [(r + 1, c), (r - 1, c)] -- UD 3 -> [(r, c - 1), (r + 1, c)] -- LD 4 -> [(r, c + 1), (r + 1, c)] -- RD 5 -> [(r, c - 1), (r - 1, c)] -- LU 6 -> [(r, c + 1), (r - 1, c)] -- RU _ -> [] in mapMaybe (toIdx (m, n)) candidates toIdx :: (Int, Int) -> (Int, Int) -> Maybe Int toIdx (m, n) (r, c) = guard (0 <= r && r < m && 0 <= c && c < n) $> (r * n + c) hasValidPath :: [[Street]] -> Bool hasValidPath grid = isLeft $ runExcept (evalStateT (dfs 0) mempty) where m = length grid n = length $ head $ fromList grid terminal = m * n - 1 neighbors = V.map (uncurry $ neighbor (m, n)) $ V.fromList $ zip [0 ..] $ concat grid adjs = V.generate (m * n) $ \i -> filter (\a -> i `elem` (neighbors V.! a)) (neighbors V.! i) dfs curr = when (curr == terminal) (throwError ()) *> modify' (IS.insert curr) *> for_ (adjs V.! curr) (unlessM <$> (gets . IS.member) <*> dfs)

先算有向图,过滤出无向子图再dfs,如果原地改状态疑似会把向量搞进老年代反而让性能下降


--【贰】--:

from typing import List class Solution: def hasValidPath(self, grid: List[List[int]]) -> bool: d = { 1: ((0, -1), (0, 1)), 2: ((-1, 0), (1, 0)), 3: ((0, -1), (1, 0)), 4: ((0, 1), (1, 0)), 5: ((0, -1), (-1, 0)), 6: ((0, 1), (-1, 0)), } m, n = len(grid), len(grid[0]) vis = [[False] * n for _ in range(m)] def dfs(i, j): if i == m - 1 and j == n - 1: return True vis[i][j] = True for di, dj in d[grid[i][j]]: ii, jj = i + di, j + dj if 0 <= ii < m and 0 <= jj < n and not vis[ii][jj]: if (-di, -dj) in d[grid[ii][jj]]: if dfs(ii, jj): return True return False return dfs(0, 0)


--【叁】--:

存下每个点的俩方向,直接从起点做一个bfs。
给负值表示走过,省点空间同时也能保持记忆。
bfs到下一个点时,确保不越界且没走过的同时,下一个点再探下一个点,确保能回得来才行。
稍后研究其他语言怎么写这坨O.o

class Solution { public: bool hasValidPath(vector<vector<int>>& grid) { int m = grid.size(),n = grid[0].size(); std::vector<std::vector<int>> dx = {{0,0},{-1,1},{0,1},{0,1},{-1,0},{-1,0}}; std::vector<std::vector<int>> dy = {{-1,1},{0,0},{-1,0},{1,0},{0,-1},{0,1}}; grid[0][0] = -grid[0][0]; queue<pair<int,int>> q; q.push(std::make_pair(0,0)); while(!q.empty()) { auto p = q.front(); q.pop(); int x = p.first,y = p.second; int id = -grid[x][y] - 1; for(int i = 0; i < 2; i++) { int nx = x + dx[id][i], ny = y + dy[id][i]; if(nx >= 0 && nx < m && ny >= 0 && ny < n && grid[nx][ny] > 0) { int nid = grid[nx][ny] - 1; for(int j = 0; j < 2; j++) { int nnx = nx + dx[nid][j], nny = ny + dy[nid][j]; if(nnx == x && nny == y) { grid[nx][ny] = -grid[nx][ny]; q.push(std::make_pair(nx,ny)); break; } } } } } return (grid[m - 1][n - 1] < 0); } };


python 的id貌似不能乱用; deque 直接当queue用;没大括号,我return缩进错了整了5分钟才发现.

class Solution: def hasValidPath(self, grid: List[List[int]]) -> bool: m,n = len(grid),len(grid[0]) dx = [[0,0],[-1,1],[0,1],[0,1],[-1,0],[-1,0]] dy = [[-1,1],[0,0],[-1,0],[1,0],[0,-1],[0,1]] q = deque() grid[0][0] = -grid[0][0] q.append([0,0]) while q: val = q.popleft() x,y = val[0], val[1] vid = -grid[x][y] - 1 for i in range(2): nx, ny = x + dx[vid][i], y + dy[vid][i] if nx >= 0 and ny >= 0 and nx < m and ny < n and grid[nx][ny] > 0: nvid = grid[nx][ny] - 1 for j in range(2): nnx, nny = nx + dx[nvid][j], ny + dy[nvid][j] if nnx == x and nny == y: grid[nx][ny] = -grid[nx][ny] q.append([nx,ny]) break return (grid[m - 1][n - 1] < 0)


不能直接用len(q)当条件; 切片当queue; go这个初化是真别扭;append用法和python区分;

func hasValidPath(grid [][]int) bool { m, n := len(grid), len(grid[0]) dx := [][]int{{0,0},{-1,1},{0,1},{0,1},{-1,0},{-1,0}} dy := [][]int{{-1,1},{0,0},{-1,0},{1,0},{0,-1},{0,1}} q := [][2]int{{0,0}} grid[0][0] = -grid[0][0] for len(q) > 0 { x, y := q[0][0], q[0][1] q = q[1:] id := -grid[x][y] - 1 for i := 0; i < 2; i++ { nx, ny := x + dx[id][i], y + dy[id][i] if nx >= 0 && ny >= 0 && nx < m && ny < n && grid[nx][ny] > 0 { nid := grid[nx][ny] - 1 for j := 0; j < 2; j++ { nnx, nny := nx + dx[nid][j], ny + dy[nid][j] if nnx == x && nny == y { q = append(q,[2]int{nx,ny}) grid[nx][ny] = -grid[nx][ny] break } } } } } return (grid[m - 1][n - 1] < 0) }