01 Matrix - Python Solution and Time Complexity Analysis


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

The distance between two adjacent cells is 1.

 

Example 1:

Input:
[[0,0,0],
 [0,1,0],
 [0,0,0]]

Output:
[[0,0,0],
 [0,1,0],
 [0,0,0]]

Example 2:

Input:
[[0,0,0],
 [0,1,0],
 [1,1,1]]

Output:
[[0,0,0],
 [0,1,0],
 [1,2,1]]

 

Note:

  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.

Understanding the Problem

The core challenge of this problem is to efficiently compute the shortest distance from each cell to the nearest cell containing a 0. This problem is significant in various applications such as image processing, pathfinding in grids, and more. A common pitfall is to use a brute-force approach, which can be highly inefficient for larger matrices.

Approach

To solve this problem, we can use a Breadth-First Search (BFS) approach. BFS is ideal for finding the shortest path in an unweighted grid. Here's a step-by-step approach:

Naive Solution

A naive solution would involve iterating over each cell and performing a BFS or DFS to find the nearest 0. This approach is not optimal as it results in a time complexity of O((m*n)^2), where m and n are the dimensions of the matrix.

Optimized Solution

We can optimize the solution by performing a multi-source BFS. The idea is to start the BFS from all 0s simultaneously. This way, we can propagate the distance to all 1s in the matrix efficiently.

Algorithm

Here is a step-by-step breakdown of the optimized algorithm:

  1. Initialize a queue and enqueue all cells containing 0.
  2. Initialize a distance matrix with infinity for all cells except those containing 0 (set to 0).
  3. Perform BFS from all 0s, updating the distance for each cell based on its neighbors.

Code Implementation

import collections

def updateMatrix(matrix):
    # Get the dimensions of the matrix
    rows, cols = len(matrix), len(matrix[0])
    
    # Initialize the distance matrix with infinity
    dist = [[float('inf')] * cols for _ in range(rows)]
    
    # Initialize the queue for BFS
    queue = collections.deque()
    
    # Enqueue all cells containing 0 and set their distance to 0
    for r in range(rows):
        for c in range(cols):
            if matrix[r][c] == 0:
                dist[r][c] = 0
                queue.append((r, c))
    
    # Directions for moving up, down, left, and right
    directions = [(1, 0), (-1, 0), (0, 1), (0, -1)]
    
    # Perform BFS
    while queue:
        r, c = queue.popleft()
        
        # Check all four directions
        for dr, dc in directions:
            nr, nc = r + dr, c + dc
            
            # If the new cell is within bounds and we found a shorter path
            if 0 <= nr < rows and 0 <= nc < cols and dist[nr][nc] > dist[r][c] + 1:
                dist[nr][nc] = dist[r][c] + 1
                queue.append((nr, nc))
    
    return dist

Complexity Analysis

The time complexity of the optimized solution is O(m*n) because each cell is enqueued and dequeued at most once. The space complexity is also O(m*n) due to the distance matrix and the queue.

Edge Cases

Potential edge cases include:

Each of these cases is handled by the BFS approach, ensuring correct distance calculations.

Testing

To test the solution comprehensively, consider the following test cases:

def test_updateMatrix():
    assert updateMatrix([[0,0,0],[0,1,0],[0,0,0]]) == [[0,0,0],[0,1,0],[0,0,0]]
    assert updateMatrix([[0,0,0],[0,1,0],[1,1,1]]) == [[0,0,0],[0,1,0],[1,2,1]]
    assert updateMatrix([[1,1,1],[1,0,1],[1,1,1]]) == [[1,1,1],[1,0,1],[1,1,1]]
    assert updateMatrix([[0]]) == [[0]]
    assert updateMatrix([[1]]) == [[float('inf')]]  # Assuming no 0s in the matrix

test_updateMatrix()

Thinking and Problem-Solving Tips

When approaching such problems, consider the following tips:

Conclusion

In this blog post, we discussed the 01 Matrix problem, explored a naive and an optimized solution, and provided a detailed explanation of the BFS approach. Understanding and solving such problems is crucial for developing strong algorithmic thinking and problem-solving skills.

Additional Resources

For further reading and practice, consider the following resources: