Welcome to Subscribe On Youtube

Formatted question description: https://leetcode.ca/all/2258.html

2258. Escape the Spreading Fire

  • Difficulty: Hard.
  • Related Topics: Array, Binary Search, Breadth-First Search, Matrix.
  • Similar Questions: Rotting Oranges, Last Day Where You Can Still Cross, Minimum Weighted Subgraph With the Required Paths.

Problem

You are given a 0-indexed 2D integer array grid of size m x n which represents a field. Each cell has one of three values:

  • 0 represents grass,

  • 1 represents fire,

  • 2 represents a wall that you and fire cannot pass through.

You are situated in the top-left cell, (0, 0), and you want to travel to the safehouse at the bottom-right cell, (m - 1, n - 1). Every minute, you may move to an adjacent grass cell. After your move, every fire cell will spread to all adjacent cells that are not walls.

Return the **maximum number of minutes that you can stay in your initial position before moving while still safely reaching the safehouse. If this is impossible, return -1. If you can **always reach the safehouse regardless of the minutes stayed, return 109.

Note that even if the fire spreads to the safehouse immediately after you have reached it, it will be counted as safely reaching the safehouse.

A cell is adjacent to another cell if the former is directly north, east, south, or west of the latter (i.e., their sides are touching).

  Example 1:

Input: grid = [[0,2,0,0,0,0,0],[0,0,0,2,2,1,0],[0,2,0,0,1,2,0],[0,0,2,2,2,0,2],[0,0,0,0,0,0,0]]
Output: 3
Explanation: The figure above shows the scenario where you stay in the initial position for 3 minutes.
You will still be able to safely reach the safehouse.
Staying for more than 3 minutes will not allow you to safely reach the safehouse.

Example 2:

Input: grid = [[0,0,0,0],[0,1,2,0],[0,2,0,0]]
Output: -1
Explanation: The figure above shows the scenario where you immediately move towards the safehouse.
Fire will spread to any cell you move towards and it is impossible to safely reach the safehouse.
Thus, -1 is returned.

Example 3:

Input: grid = [[0,0,0],[2,2,0],[1,2,0]]
Output: 1000000000
Explanation: The figure above shows the initial grid.
Notice that the fire is contained by walls and you will always be able to safely reach the safehouse.
Thus, 109 is returned.

  Constraints:

  • m == grid.length

  • n == grid[i].length

  • 2 <= m, n <= 300

  • 4 <= m * n <= 2 * 104

  • grid[i][j] is either 0, 1, or 2.

  • grid[0][0] == grid[m - 1][n - 1] == 0

Solution

  • class Solution {
        private int[][] setFire(int[][] grid, int[][] dir) {
            int n = grid.length;
            int m = grid[0].length;
            ArrayDeque<Integer> bfs = new ArrayDeque<>();
            int[][] fire = new int[n][m];
            for (int i = 0; i < n; i++) {
                for (int j = 0; j < m; j++) {
                    fire[i][j] = Integer.MAX_VALUE;
                    if (grid[i][j] == 1) {
                        fire[i][j] = 0;
                        bfs.add(i * m + j);
                    }
                    if (grid[i][j] == 2) {
                        fire[i][j] = 0;
                    }
                }
            }
            while (!bfs.isEmpty()) {
                int rm = bfs.removeFirst();
                int x = rm / m;
                int y = rm % m;
                for (int d = 0; d < 4; d++) {
                    int nx = x + dir[d][0];
                    int ny = y + dir[d][1];
                    if (nx >= 0 && ny >= 0 && nx < n && ny < m && fire[nx][ny] == Integer.MAX_VALUE) {
                        fire[nx][ny] = fire[x][y] + 1;
                        bfs.add(nx * m + ny);
                    }
                }
            }
            return fire;
        }
    
        private boolean isPoss(int[][] fire, int[][] dir, int time) {
            if (time >= fire[0][0]) {
                return false;
            }
            int n = fire.length;
            int m = fire[0].length;
            ArrayDeque<Integer> bfs = new ArrayDeque<>();
            bfs.add(0);
            boolean[][] isVis = new boolean[n][m];
            isVis[0][0] = true;
            while (!bfs.isEmpty()) {
                int size = bfs.size();
                while (size-- > 0) {
                    int rm = bfs.removeFirst();
                    int x = rm / m;
                    int y = rm % m;
                    if (x == n - 1 && y == m - 1) {
                        return true;
                    }
                    for (int d = 0; d < 4; d++) {
                        int nx = x + dir[d][0];
                        int ny = y + dir[d][1];
                        if (nx >= 0 && ny >= 0 && nx < n && ny < m && !isVis[nx][ny]) {
                            if (nx == n - 1 && ny == m - 1) {
                                if (time + 1 <= fire[nx][ny]) {
                                    isVis[nx][ny] = true;
                                    bfs.add(nx * m + ny);
                                }
                            } else {
                                if (time + 1 < fire[nx][ny]) {
                                    isVis[nx][ny] = true;
                                    bfs.add(nx * m + ny);
                                }
                            }
                        }
                    }
                }
                time++;
            }
            return false;
        }
    
        public int maximumMinutes(int[][] grid) {
            int[][] dir = { {0, 1}, {1, 0}, {-1, 0}, {0, -1} };
            int[][] fire = setFire(grid, dir);
            int lo = 0;
            int hi = (int) 1e9;
            while (lo <= hi) {
                int mid = ((hi - lo) >> 1) + lo;
                if (isPoss(fire, dir, mid)) {
                    lo = mid + 1;
                } else {
                    hi = mid - 1;
                }
            }
            return hi;
        }
    }
    
    ############
    
    class Solution {
        private static int[] dirs = {-1, 0, 1, 0, -1};
        private int[][] grid;
        private int m;
        private int n;
    
        public int maximumMinutes(int[][] grid) {
            this.grid = grid;
            m = grid.length;
            n = grid[0].length;
            int left = -1, right = m * n;
            while (left < right) {
                int mid = (left + right + 1) >> 1;
                if (check(mid)) {
                    left = mid;
                } else {
                    right = mid - 1;
                }
            }
            return left == m * n ? (int) 1e9 : left;
        }
    
        private boolean check(int t) {
            boolean[][] fire = new boolean[m][n];
            Deque<int[]> f = new ArrayDeque<>();
            for (int i = 0; i < m; ++i) {
                for (int j = 0; j < n; ++j) {
                    if (grid[i][j] == 1) {
                        fire[i][j] = true;
                        f.offer(new int[] {i, j});
                    }
                }
            }
            while (t-- > 0 && !f.isEmpty()) {
                f = spread(fire, f);
            }
            if (fire[0][0]) {
                return false;
            }
            Deque<int[]> q = new ArrayDeque<>();
            boolean[][] vis = new boolean[m][n];
            q.offer(new int[] {0, 0});
            vis[0][0] = true;
            while (!q.isEmpty()) {
                for (int i = q.size(); i > 0; --i) {
                    int[] p = q.poll();
                    if (fire[p[0]][p[1]]) {
                        continue;
                    }
                    for (int k = 0; k < 4; ++k) {
                        int x = p[0] + dirs[k], y = p[1] + dirs[k + 1];
                        if (x >= 0 && x < m && y >= 0 && y < n && !fire[x][y] && !vis[x][y]
                            && grid[x][y] == 0) {
                            if (x == m - 1 && y == n - 1) {
                                return true;
                            }
                            vis[x][y] = true;
                            q.offer(new int[] {x, y});
                        }
                    }
                }
                f = spread(fire, f);
            }
            return false;
        }
    
        private Deque<int[]> spread(boolean[][] fire, Deque<int[]> q) {
            Deque<int[]> nf = new ArrayDeque<>();
            while (!q.isEmpty()) {
                int[] p = q.poll();
                for (int k = 0; k < 4; ++k) {
                    int x = p[0] + dirs[k], y = p[1] + dirs[k + 1];
                    if (x >= 0 && x < m && y >= 0 && y < n && !fire[x][y] && grid[x][y] == 0) {
                        fire[x][y] = true;
                        nf.offer(new int[] {x, y});
                    }
                }
            }
            return nf;
        }
    }
    
  • class Solution:
        def maximumMinutes(self, grid: List[List[int]]) -> int:
            def spread(fire, q):
                nf = deque()
                while q:
                    i, j = q.popleft()
                    for a, b in [[0, -1], [0, 1], [-1, 0], [1, 0]]:
                        x, y = i + a, j + b
                        if 0 <= x < m and 0 <= y < n and not fire[x][y] and grid[x][y] == 0:
                            fire[x][y] = True
                            nf.append((x, y))
                return nf
    
            def check(t):
                fire = [[False] * n for _ in range(m)]
                f = deque()
                for i, row in enumerate(grid):
                    for j, v in enumerate(row):
                        if v == 1:
                            fire[i][j] = True
                            f.append((i, j))
                while t and f:
                    f = spread(fire, f)
                    t -= 1
                if fire[0][0]:
                    return False
                q = deque([(0, 0)])
                vis = [[False] * n for _ in range(m)]
                vis[0][0] = True
                while q:
                    for _ in range(len(q)):
                        i, j = q.popleft()
                        if fire[i][j]:
                            continue
                        for a, b in [[0, -1], [0, 1], [-1, 0], [1, 0]]:
                            x, y = i + a, j + b
                            if (
                                0 <= x < m
                                and 0 <= y < n
                                and not fire[x][y]
                                and not vis[x][y]
                                and grid[x][y] == 0
                            ):
                                if x == m - 1 and y == n - 1:
                                    return True
                                vis[x][y] = True
                                q.append((x, y))
                    f = spread(fire, f)
                return False
    
            m, n = len(grid), len(grid[0])
            left, right = -1, m * n
            while left < right:
                mid = (left + right + 1) >> 1
                if check(mid):
                    left = mid
                else:
                    right = mid - 1
            return int(1e9) if left == m * n else left
    
    ############
    
    # 2258. Escape the Spreading Fire
    # https://leetcode.com/problems/escape-the-spreading-fire/
    
    class Solution:
        def maximumMinutes(self, grid: List[List[int]]) -> int:
            rows, cols = len(grid), len(grid[0])
            INF = 10 ** 10
            dist = [[INF] * cols for _ in range(rows)]
            fire = deque()
            
            for x in range(rows):
                for y in range(cols):
                    if grid[x][y] == 1:
                        dist[x][y] = 0
                        fire.append((0, x, y))
            
            while fire:
                d, x, y = fire.popleft()
    
                for dx, dy in [(x + 1, y), (x - 1, y), (x, y + 1), (x, y - 1)]:
                    if 0 <= dx < rows and 0 <= dy < cols and grid[dx][dy] != 2 and dist[dx][dy] == INF:
                        dist[dx][dy] = d + 1
                        fire.append((d + 1, dx, dy))
            
            def good(k):
                if dist[0][0] <= k: return False
                
                queue = deque([(k, 0, 0)])
                visited = [[False] * cols for _ in range(rows)]
    
                while queue:
                    d, x, y = queue.popleft()
    
                    for dx, dy in [(x + 1, y), (x - 1, y), (x, y + 1), (x, y - 1)]:
                        if 0 <= dx < rows and 0 <= dy < cols and grid[dx][dy] != 2 and not visited[dx][dy] and d + 1 < dist[dx][dy]:
                            visited[dx][dy] = True
                            queue.append((d + 1, dx, dy))
                            
                            if dx == rows - 1 and dy == cols - 1: 
                                return True
                        
                        if dx == rows - 1 and dy == cols - 1 and grid[dx][dy] != 2 and not visited[dx][dy] and d + 1 <= dist[dx][dy]: 
                            return True
    
                
                return False
    
            left, right = 0, 10 ** 9
            
            while left < right:
                mid = (left + right + 1) // 2
    
                if good(mid):
                    left = mid
                else:
                    right = mid - 1
            
            if left == 0:
                return 0 if good(0) else -1
                    
            return left
    
    
    
  • class Solution {
    public:
        vector<int> dirs = {-1, 0, 1, 0, -1};
    
        int maximumMinutes(vector<vector<int>>& grid) {
            int m = grid.size(), n = grid[0].size();
            int left = -1, right = m * n;
            while (left < right) {
                int mid = (left + right + 1) >> 1;
                if (check(mid, grid))
                    left = mid;
                else
                    right = mid - 1;
            }
            return left == m * n ? 1e9 : left;
        }
    
        bool check(int t, vector<vector<int>>& grid) {
            int m = grid.size(), n = grid[0].size();
            vector<vector<bool>> fire(m, vector<bool>(n));
            queue<vector<int>> f;
            for (int i = 0; i < m; ++i) {
                for (int j = 0; j < n; ++j) {
                    if (grid[i][j] == 1) {
                        fire[i][j] = true;
                        f.push({i, j});
                    }
                }
            }
            while (t-- && f.size()) f = spread(fire, f, grid);
            queue<vector<int>> q;
            vector<vector<bool>> vis(m, vector<bool>(n));
            q.push({0, 0});
            vis[0][0] = true;
            while (!q.empty()) {
                for (int i = q.size(); i > 0; --i) {
                    auto p = q.front();
                    q.pop();
                    if (fire[p[0]][p[1]]) continue;
                    for (int k = 0; k < 4; ++k) {
                        int x = p[0] + dirs[k], y = p[1] + dirs[k + 1];
                        if (x >= 0 && x < m && y >= 0 && y < n && !fire[x][y] && !vis[x][y] && grid[x][y] == 0) {
                            if (x == m - 1 && y == n - 1) return true;
                            vis[x][y] = true;
                            q.push({x, y});
                        }
                    }
                }
                f = spread(fire, f, grid);
            }
            return false;
        }
    
        queue<vector<int>> spread(vector<vector<bool>>& fire, queue<vector<int>>& f, vector<vector<int>>& grid) {
            queue<vector<int>> nf;
            int m = grid.size(), n = grid[0].size();
            while (!f.empty()) {
                auto p = f.front();
                f.pop();
                for (int k = 0; k < 4; ++k) {
                    int x = p[0] + dirs[k], y = p[1] + dirs[k + 1];
                    if (x >= 0 && x < m && y >= 0 && y < n && !fire[x][y] && grid[x][y] == 0) {
                        fire[x][y] = true;
                        nf.push({x, y});
                    }
                }
            }
            return nf;
        }
    };
    
  • func maximumMinutes(grid [][]int) int {
    	m, n := len(grid), len(grid[0])
    	dirs := []int{-1, 0, 1, 0, -1}
    
    	spread := func(fire [][]bool, q [][]int) [][]int {
    		nf := [][]int{}
    		for len(q) > 0 {
    			p := q[0]
    			q = q[1:]
    			for k := 0; k < 4; k++ {
    				x, y := p[0]+dirs[k], p[1]+dirs[k+1]
    				if x >= 0 && x < m && y >= 0 && y < n && !fire[x][y] && grid[x][y] == 0 {
    					fire[x][y] = true
    					nf = append(nf, []int{x, y})
    				}
    			}
    		}
    		return nf
    	}
    
    	check := func(t int) bool {
    		fire := make([][]bool, m)
    		vis := make([][]bool, m)
    		f := [][]int{}
    		for i, row := range grid {
    			fire[i] = make([]bool, n)
    			vis[i] = make([]bool, n)
    			for j, v := range row {
    				if v == 1 {
    					fire[i][j] = true
    					f = append(f, []int{i, j})
    				}
    			}
    		}
    		for t > 0 && len(f) > 0 {
    			f = spread(fire, f)
    			t--
    		}
    		if fire[0][0] {
    			return false
    		}
    		q := [][]int{ {0, 0} }
    		vis[0][0] = true
    		for len(q) > 0 {
    			for i := len(q); i > 0; i-- {
    				p := q[0]
    				q = q[1:]
    				if fire[p[0]][p[1]] {
    					continue
    				}
    				for k := 0; k < 4; k++ {
    					x, y := p[0]+dirs[k], p[1]+dirs[k+1]
    					if x >= 0 && x < m && y >= 0 && y < n && !fire[x][y] && !vis[x][y] && grid[x][y] == 0 {
    						if x == m-1 && y == n-1 {
    							return true
    						}
    						vis[x][y] = true
    						q = append(q, []int{x, y})
    					}
    				}
    			}
    			f = spread(fire, f)
    		}
    		return false
    	}
    
    	left, right := -1, m*n
    	for left < right {
    		mid := (left + right + 1) >> 1
    		if check(mid) {
    			left = mid
    		} else {
    			right = mid - 1
    		}
    	}
    	if left == m*n {
    		return int(1e9)
    	}
    	return left
    }
    
  • function maximumMinutes(grid: number[][]): number {
        const m = grid.length;
        const n = grid[0].length;
        const fire = Array.from({ length: m }, () => Array.from({ length: n }, () => false));
        const vis = Array.from({ length: m }, () => Array.from({ length: n }, () => false));
        const dirs: number[] = [-1, 0, 1, 0, -1];
        let [l, r] = [-1, m * n];
        const spread = (q: number[][]): number[][] => {
            const nq: number[][] = [];
            while (q.length) {
                const [i, j] = q.shift()!;
                for (let k = 0; k < 4; ++k) {
                    const [x, y] = [i + dirs[k], j + dirs[k + 1]];
                    if (x >= 0 && x < m && y >= 0 && y < n && !fire[x][y] && grid[x][y] === 0) {
                        fire[x][y] = true;
                        nq.push([x, y]);
                    }
                }
            }
            return nq;
        };
        const check = (t: number): boolean => {
            for (let i = 0; i < m; ++i) {
                fire[i].fill(false);
                vis[i].fill(false);
            }
            let q1: number[][] = [];
            for (let i = 0; i < m; ++i) {
                for (let j = 0; j < n; ++j) {
                    if (grid[i][j] === 1) {
                        q1.push([i, j]);
                        fire[i][j] = true;
                    }
                }
            }
            for (; t && q1.length; --t) {
                q1 = spread(q1);
            }
            if (fire[0][0]) {
                return false;
            }
            const q2: number[][] = [[0, 0]];
            vis[0][0] = true;
            for (; q2.length; q1 = spread(q1)) {
                for (let d = q2.length; d; --d) {
                    const [i, j] = q2.shift()!;
                    if (fire[i][j]) {
                        continue;
                    }
                    for (let k = 0; k < 4; ++k) {
                        const [x, y] = [i + dirs[k], j + dirs[k + 1]];
                        if (
                            x >= 0 &&
                            x < m &&
                            y >= 0 &&
                            y < n &&
                            !vis[x][y] &&
                            !fire[x][y] &&
                            grid[x][y] === 0
                        ) {
                            if (x === m - 1 && y === n - 1) {
                                return true;
                            }
                            vis[x][y] = true;
                            q2.push([x, y]);
                        }
                    }
                }
            }
            return false;
        };
        while (l < r) {
            const mid = (l + r + 1) >> 1;
            if (check(mid)) {
                l = mid;
            } else {
                r = mid - 1;
            }
        }
        return l === m * n ? 1e9 : l;
    }
    
    

Explain:

nope.

Complexity:

  • Time complexity : O(n).
  • Space complexity : O(n).

All Problems

All Solutions