Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
72 changes: 72 additions & 0 deletions day19/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
question of the day: https://leetcode.com/problems/01-matrix/#/description

Given a matrix consists of 0 and 1, find the distance of
the nearest 0 for each cell.

The distance between two adjacent cells is 1.

*Example 1:*

Input:

```ruby
0 0 0
0 1 0
0 0 0
```

Output:

```ruby
0 0 0
0 1 0
0 0 0
```

*Example 2:*

Input:

```ruby
0 0 0
0 1 0
1 1 1
```

Output:

```ruby
0 0 0
0 1 0
1 2 1
```

Assumptions we can make:

1. The number of elements of the given matrix will not exceed 10,000.
2. There are at least one 0 in the given matrix.
3. The cells are adjacent in only four directions: up, down, left and right.

## Ideas

This is like drawing out a contour map. The 0's are the peaks of
hills and mountains, while the parts of the matrix that are far away
from any 0's are like the valleys.

We can start from each peak and go outwards. It'd be a BFS-like
approach. Do a search through the whole matrix once first and find
where all the 0's are. Add each of those positions into a queue,
and then use that queue to start off a BFS. During this BFS, we
check the neighboring cells to see what the minimal value is that
we can place in this cell.

This solution is `O(n)` to find the 0s, and then `O(n)` to run the
BFS. My implementation also requires `O(n)` space, although I think
it's possible to modify the matrix in-place with some more clever
checking.

## Code

[Ruby](./matrixCountours.rb)

## Follow up
108 changes: 108 additions & 0 deletions day19/matrixCountours.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
def contourDistances(matrix)
rows, cols = matrix.size, matrix[0].size

if rows == 0 || cols == 0
return matrix
end

contours = Array.new(rows).map { |x| [nil] * cols }
queue = []
# start by finding 0s
for row in 0..rows-1
for col in 0..cols-1
if matrix[row][col] == 0
queue << [row, col]
contours[row][col] = 0
end
end
end

# do bfs
while queue.size > 0
current = queue.shift
row, col = current
contours[row][col] = getMinNeighbor(contours, row, col) + 1
for i, j in [[row-1, col], [row, col-1], [row, col+1], [row+1, col]]
if withinBounds([i, j], rows, cols) && contours[i][j] == nil
queue << [i, j]
end
end
end

contours
end

def withinBounds(coordinate, rows, cols)
x, y = coordinate
x >= 0 && x < rows && y >= 0 && y < cols
end

def getMinNeighbor(matrix, row, col)
if matrix[row][col] == 0
return -1
end

vals = []
rows, cols = matrix.size, matrix[0].size
for i, j in [[row-1, col], [row, col-1], [row, col+1], [row+1, col]]
if withinBounds([i, j], rows, cols)
if matrix[i][j] != nil
vals << matrix[i][j]
end
end
end

vals.min
end

#########
# Tests #
#########

class AssertionError < RuntimeError
end

def assert &block
raise AssertionError unless yield
end

def tests
# edge cases
empty = [[]]
emptyOutput = [[]]
assert { contourDistances(empty) == emptyOutput }

one = [[0]]
oneOutput = [[0]]
assert { contourDistances(one) == oneOutput }

# other cases
matrix = [[1,1,1],
[1,0,1],
[1,1,1]]

output = [[2,1,2],
[1,0,1],
[2,1,2]]
assert { contourDistances(matrix) == output }

matrix1 = [[0,0,0],
[0,1,0],
[0,0,0]]

output1 = [[0,0,0],
[0,1,0],
[0,0,0]]
assert { contourDistances(matrix1) == output1 }

matrix2 = [[0,0,0],
[0,1,0],
[1,1,1]]

output2 = [[0,0,0],
[0,1,0],
[1,2,1]]
assert { contourDistances(matrix2) == output2 }
end

tests()