Data Structures

Pacific Atlantic Waterflow

3 months, 3 weeks ago ; 82 views
Share this

 In this solution, the aim is to find cells that can flow water to both the Pacific Ocean and the Atlantic Ocean.

The problem considers a height map where water can only flow from a cell to a neighboring cell with a non-negative height difference (i.e., water flows from higher to lower ground).

We are simply identifying cells that can drain water to both the Pacific Ocean (left and top borders) and the Atlantic Ocean (right and bottom borders).

                   Pacific Ocean


                   1   2   2   3   5

Pacific         3   2   3   4   4       Atlantic

ocean          6   7   1   4   5       ocean

                    5   1   1   2   4

                    Atlantic ocean

 

Solution

The solution to the Pacific Atlantic water flow problem involves simulating the water flow from the edges of the grid towards the inner cells using Depth-First Search (DFS). The primary thought process can be broken down as follows:

Grid Definition

  •         We have a grid of heights where each cell contains the height of the terrain at that point.
  •         Water can flow from a cell to its adjacent cells (up, down, left, right) if the adjacent cell has an equal or lower height.

Pacific and Atlantic Oceans

  •         Water can flow into the Pacific Ocean if it starts from any cell on the left or top edges of the grid.
  •         Water can flow into the Atlantic Ocean if it starts from any cell on the right or bottom edges of the grid.

The goal is to Identify all cells from which water can flow to both the Pacific and Atlantic Oceans.

class Solution:

    def pacificAtlantic(self, heights: List[List[int]]) -> List[List[int]]:
        """
        Finds all cells that can flow water to both the Pacific Ocean and the Atlantic Ocean.

        Args:
            heights (List[List[int]]): A 2D list representing the height map, where heights[r][c] represents the height
                                       of cell (row r, column c).

        Returns:
            List[List[int]]: A list of lists containing the coordinates (row, column) of cells that can flow water
                             to both the Pacific and Atlantic Oceans.
        """
        if not heights:
            return []

        num_rows, num_cols = len(heights), len(heights[0])
        pacific_reachable = set()  # Cells reachable from the Pacific Ocean
        atlantic_reachable = set()  # Cells reachable from the Atlantic Ocean

        def dfs(row, col, visited, prev_height):
            """
            Performs a Depth-First Search (DFS) traversal to explore reachable cells from a given starting point.

            Args:
                row (int): The row index of the current cell.
                col (int): The column index of the current cell.
                visited (set): A set of visited cells to avoid revisiting.
                prev_height (int): The height of the previous cell to ensure water can flow downwards.
            """

            if (row, col) in visited or \
               row < 0 or col < 0 or row >= num_rows or col >= num_cols or \
               heights[row][col] < prev_height:
                return

            visited.add((row, col))
            dfs(row + 1, col, visited, heights[row][col])  # Explore down
            dfs(row - 1, col, visited, heights[row][col])  # Explore up
            dfs(row, col + 1, visited, heights[row][col])  # Explore right
            dfs(row, col - 1, visited, heights[row][col])  # Explore left

        # Start DFS from all cells on the borders (Pacific and Atlantic)
        for col in range(num_cols):
            dfs(0, col, pacific_reachable, heights[0][col])  # Pacific Ocean (top border)
            dfs(num_rows - 1, col, atlantic_reachable, heights[num_rows - 1][col])  # Atlantic Ocean (bottom border)

        for row in range(num_rows):
            dfs(row, 0, pacific_reachable, heights[row][0])  # Pacific Ocean (left border)
            dfs(row, num_cols - 1, atlantic_reachable, heights[row][num_cols - 1])  # Atlantic Ocean (right border)

        # Find cells reachable from both oceans
        result = []
        for row in range(num_rows):
            for col in range(num_cols):
                if (row, col) in pacific_reachable and (row, col) in atlantic_reachable:
                    result.append([row, col])

        return result

Strategy to the Solution

Initialization

  •         Use two sets to keep track of cells that can reach the Pacific and Atlantic Oceans (pacific_reachable and atlantic_reachable).

DFS for Water Flow Simulation

  •         Use DFS to simulate water flowing from the ocean edges into the grid.
  •         Start the DFS from all cells on the Pacific border (left and top edges) and mark all reachable cells in pacific_reachable.
  •         Similarly, start the DFS from all cells on the Atlantic border (right and bottom edges) and mark all reachable cells in atlantic_reachable.

Combining Results

  •         Cells that are present in both pacific_reachable and atlantic_reachable are the cells from which water can flow to both oceans.
  •         Return these cells as the result.

 

Time Complexity

The time complexity is determined by the number of cells in the grid and the operations performed on each cell.

DFS Traversal

  •         Each cell in the grid can be visited multiple times: once for the DFS starting from the Pacific Ocean border and once for the DFS starting from the Atlantic Ocean border.
  •         In the worst case, each DFS might visit all cells in the grid.
  •         Therefore, the time complexity of the DFS part is O(m multiplied by n) for the Pacific Ocean and O(m multiplied by n) for the Atlantic Ocean, where m is the number of rows and n is the number of columns.

Overall DFS

  •         Since we perform two separate DFS traversals (one for each ocean), the total time complexity is 2 (m multiplied by n)=O(m multiplied by n).

 

Space Complexity

The space complexity is influenced by the space required for storing visited cells and the call stack for DFS.

Visited Sets

  •         We maintain two sets (pacific_reachable and atlantic_reachable) to store the cells reachable from each ocean.
  •         Each set can store up to m×nm×n cells in the worst case.
  •         Thus, the space complexity for the visited sets is 
``` O(m×n) ```

 

Call Stack for DFS

  •         The maximum depth of the DFS call stack is the maximum number of cells that can be traversed in a single DFS call.
  •         In the worst case, this depth can be
```m×n```

 

  •         However, the depth of the DFS stack is typically limited by the number of rows or columns, giving a space complexity of

``` Big -O of the maximum between m and n ```

for the call stack.

 

Unit tests

Here are sample test cases to establish the accuracy and robustness of this solution.

import unittest
from typing import List

class TestPacificAtlantic(unittest.TestCase):

    def setUp(self):
        self.solution = Solution()
        
    def test_example_case(self):
        # Example height map
        heights = [
            [1, 2, 2, 3, 5],
            [3, 2, 3, 4, 4],
            [2, 4, 5, 3, 1],
            [6, 7, 1, 4, 5],
            [5, 1, 1, 2, 4]
        ]

        expected_result = [[0, 4], [1, 3], [1, 4], [2, 2], [3, 0], [3, 1], [4, 0]]
        actual_result = self.solution.pacificAtlantic(heights)

        self.assertEqual(sorted(actual_result), sorted(expected_result))

    def test_empty_heights(self):
        # Test with an empty height map
        heights = []

        actual_result = self.solution.pacificAtlantic(heights)

        self.assertEqual(actual_result, [])

    # Add more test cases as needed

if __name__ == "__main__":
    unittest.main()

 

Become a member
Get the latest news right in your inbox. We never spam!

Read next

Island Perimeter

&nbsp;This solution seeks to find the perimeter of an island in a grid.&nbsp; The problem considers a grid where each cell represents land (1) or … Read More

Kibsoft 3 months, 3 weeks ago . 75 views

Clone Graph

3 months, 3 weeks ago . 62 views