Skip to content

Commit 5d1d030

Browse files
committed
LeetCode 1162. As Far from Land as Possible
1 parent c4aaa7a commit 5d1d030

File tree

3 files changed

+172
-1
lines changed

3 files changed

+172
-1
lines changed

README.md

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -341,6 +341,7 @@ Solutions to LeetCode problems. The first column links to the problem in LeetCod
341341
| [1137. N-th Tribonacci Number][lc1137] | 🟢 Easy | [![python](res/py.png)][lc1137py] [![rust](res/rs.png)][lc1137rs] |
342342
| [1143. Longest Common Subsequence][lc1143] | 🟠 Medium | [![python](res/py.png)][lc1143py] |
343343
| [1155. Number of Dice Rolls With Target Sum][lc1155] | 🟠 Medium | [![python](res/py.png)][lc1155py] |
344+
| [1162. As Far from Land as Possible][lc1162] | 🟠 Medium | [![python](res/py.png)][lc1162py] [![rust](res/rs.png)][lc1162rs] |
344345
| [1207. Unique Number of Occurrences][lc1207] | 🟢 Easy | [![python](res/py.png)][lc1207py] |
345346
| [1220. Count Vowels Permutation][lc1220] | 🔴 Hard | [![python](res/py.png)][lc1220py] |
346347
| [1235. Maximum Profit in Job Scheduling][lc1235] | 🔴 Hard | [![python](res/py.png)][lc1235py] |
@@ -1084,7 +1085,10 @@ Solutions to LeetCode problems. The first column links to the problem in LeetCod
10841085
[lc1143]: https://leetcode.com/problems/longest-common-subsequence/
10851086
[lc1143py]: leetcode/longest-common-subsequence.py
10861087
[lc1155]: https://leetcode.com/problems/number-of-dice-rolls-with-target-sum/
1087-
[lc1155py]: ../number-of-dice-rolls-with-target-sum.py
1088+
[lc1155py]: leetcode/number-of-dice-rolls-with-target-sum.py
1089+
[lc1162]: https://leetcode.com/problems/as-far-from-land-as-possible/
1090+
[lc1162py]: leetcode/as-far-from-land-as-possible.py
1091+
[lc1162rs]: leetcode/as-far-from-land-as-possible.rs
10881092
[lc1207]: https://leetcode.com/problems/unique-number-of-occurrences/
10891093
[lc1207py]: leetcode/unique-number-of-occurrences.py
10901094
[lc1220]: https://leetcode.com/problems/count-vowels-permutation/
Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,91 @@
1+
# 1162. As Far from Land as Possible
2+
# 🟠 Medium
3+
#
4+
# https://leetcode.com/problems/as-far-from-land-as-possible/
5+
#
6+
# Tags: Array - Dynamic Programming - Breadth-First Search - Matrix
7+
8+
import timeit
9+
from typing import List
10+
11+
12+
# Use BFS and a matrix with the current shortest distance between any
13+
# cell and land to compute the shortest distance between any cell and
14+
# land, we will only revisit cells when the new distance to land is
15+
# less than the shortest previous distance found, which may, in turn,
16+
# influence its neighbors by providing a shorter path to land.
17+
#
18+
# Time complexity: O(m+n) - We can travel a maximum of n levels, on each
19+
# level, we will only visit cells to which we have not previously found
20+
# a shorter route, in total we will visit m*n cells during the BFS.
21+
# Space complexity: O(m+n) - The distance matrix has the same size as
22+
# the input matrix, m rows and n columns.
23+
#
24+
# Runtime 548 ms Beats 82.97%
25+
# Memory 14.6 MB Beats 64.75%
26+
class Solution:
27+
def maxDistance(self, grid: List[List[int]]) -> int:
28+
m, n = len(grid), len(grid[0])
29+
# A matrix of distances to land.
30+
dist = [[float("inf")] * n for _ in range(m)]
31+
# Use a stack to do a per-level BFS.
32+
current_level, level = [], 0
33+
# Add land cells to the first level.
34+
for i in range(m):
35+
for j in range(n):
36+
if grid[i][j] == 1:
37+
current_level.append((i, j))
38+
# Mark this cell as 0 units away from land.
39+
dist[i][j] = 0
40+
# If the grid has no water or land, return -1.
41+
if not len(current_level) or len(current_level) == (m * n):
42+
return -1
43+
# Keep exploring as long as the current level has any elements.
44+
while current_level:
45+
next_level = []
46+
level += 1
47+
# Process one level at a time.
48+
for _ in range(len(current_level)):
49+
r, c = current_level.pop()
50+
for nr, nc in ((r + 1, c), (r - 1, c), (r, c + 1), (r, c - 1)):
51+
# The cell needs to be within boundaries, it should
52+
# not be land and we should not have a shorter path
53+
# to land already.
54+
if 0 <= nr < m and 0 <= nc < n and level < dist[nr][nc]:
55+
dist[nr][nc] = level
56+
next_level.append((nr, nc))
57+
current_level = next_level
58+
return level - 1
59+
60+
61+
def test():
62+
executors = [Solution]
63+
tests = [
64+
[[[1]], -1],
65+
[[[0]], -1],
66+
[[[0, 0], [0, 0], [0, 0]], -1],
67+
[[[1, 1], [1, 1], [1, 1]], -1],
68+
[[[1, 0], [0, 0], [1, 0]], 2],
69+
[[[1, 0, 1], [0, 0, 0], [1, 0, 1]], 2],
70+
[[[1, 0, 0], [0, 0, 0], [0, 0, 0]], 4],
71+
[[[0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0]], -1],
72+
]
73+
for executor in executors:
74+
start = timeit.default_timer()
75+
for _ in range(1):
76+
for col, t in enumerate(tests):
77+
sol = executor()
78+
result = sol.maxDistance(t[0])
79+
exp = t[1]
80+
assert result == exp, (
81+
f"\033[93m» {result} <> {exp}\033[91m for"
82+
+ f" test {col} using \033[1m{executor.__name__}"
83+
)
84+
stop = timeit.default_timer()
85+
used = str(round(stop - start, 5))
86+
cols = "{0:20}{1:10}{2:10}"
87+
res = cols.format(executor.__name__, used, "seconds")
88+
print(f"\033[92m» {res}\033[0m")
89+
90+
91+
test()
Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
// 1162. As Far from Land as Possible
2+
// 🟠 Medium
3+
//
4+
// https://leetcode.com/problems/as-far-from-land-as-possible/
5+
//
6+
// Tags: Array - Dynamic Programming - Breadth-First Search - Matrix
7+
8+
struct Solution;
9+
impl Solution {
10+
// Use BFS and a matrix with the current shortest distance between any
11+
// cell and land to compute the shortest distance between any cell and
12+
// land, we will only revisit cells when the new distance to land is
13+
// less than the shortest previous distance found, which may, in turn,
14+
// influence its neighbors by providing a shorter path to land.
15+
//
16+
// Time complexity: O(m+n) - We can travel a maximum of n levels, on each
17+
// level, we will only visit cells to which we have not previously found
18+
// a shorter route, in total we will visit m*n cells during the BFS.
19+
// Space complexity: O(m+n) - The distance matrix has the same size as
20+
// the input matrix, m rows and n columns.
21+
//
22+
// Runtime 12 ms Beats 66.67%
23+
// Memory 2.3 MB Beats 93.33%
24+
pub fn max_distance(grid: Vec<Vec<i32>>) -> i32 {
25+
let m = grid.len();
26+
let n = grid[0].len();
27+
let mut dist: Vec<Vec<usize>> = vec![vec![1000; n]; m];
28+
let mut current_level: Vec<(i16, i16)> = vec![];
29+
let mut level: usize = 0;
30+
for i in 0..m {
31+
for j in 0..n {
32+
if grid[i][j] == 1 {
33+
current_level.push((i as i16, j as i16));
34+
dist[i][j] = 0;
35+
}
36+
}
37+
}
38+
if current_level.len() == 0 || current_level.len() == (m * n) {
39+
return -1;
40+
}
41+
while current_level.len() > 0 {
42+
let mut next_level = Vec::<(i16, i16)>::new();
43+
level += 1;
44+
// Process the current entire level.
45+
for _ in 0..current_level.len() {
46+
let (r, c) = current_level.pop().unwrap();
47+
for (nr, nc) in [(r + 1, c), (r - 1, c), (r, c + 1), (r, c - 1)] {
48+
if 0 <= nr
49+
&& nr < m as i16
50+
&& 0 <= nc
51+
&& nc < n as i16
52+
&& level < dist[nr as usize][nc as usize]
53+
{
54+
dist[nr as usize][nc as usize] = level;
55+
next_level.push((nr, nc));
56+
}
57+
}
58+
}
59+
current_level = next_level;
60+
}
61+
(level - 1) as i32
62+
}
63+
}
64+
65+
// Tests.
66+
fn main() {
67+
assert_eq!(
68+
Solution::max_distance(vec![vec![1, 0, 1], vec![0, 0, 0], vec![1, 0, 1]]),
69+
2
70+
);
71+
assert_eq!(
72+
Solution::max_distance(vec![vec![1, 0, 0], vec![0, 0, 0], vec![0, 0, 0]]),
73+
4
74+
);
75+
println!("All tests passed!")
76+
}

0 commit comments

Comments
 (0)