Start learning free

LESSON 359 OF 410 · GRAPHS

01 Matrix - Python Solution and Time Complexity Analysis

Practice O(n * m) Read the full explanation

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.
STEP 1 OF 15
    Ctrl + Enter to check

    PYTHON · GRAPHS

    01 Matrix in Python, explained

    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:

    • A matrix with all 0s.
    • A matrix with all 1s except one 0.
    • Single row or single column matrices.

    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:

    • Understand the problem constraints and edge cases.
    • Think about the most efficient data structures and algorithms (e.g., BFS for shortest path problems).
    • Break down the problem into smaller, manageable parts.
    • Practice similar problems to improve problem-solving skills.

    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:

    Keep going with PythonAbout 340 step-by-step lessons, from your first line of code to coding interviews. Free to start.
    Start learning free