cswork / libraryOpen practice workspace

Coding questions · Airbnb

Simulate pouring water onto a 1D terrain

This question evaluates understanding of simulation of discrete physical processes, array manipulation, state tracking, and greedy/local-search movement rules, measuring algorithmic design and efficiency competencies.

You are given a 1D terrain represented by an integer array heights, where heights[i] is the height of the column at index i.

Part 1 — Render terrain

Write a function to print an ASCII visualization of the terrain where:

  • Each column is drawn using + characters.
  • The bottom row (base layer) is always shown.
  • Rows are printed from top to bottom.

Example input:

  • heights = [5,4,3,2,1,3,4,0,3,4]

Example rendering (one possible formatting):

+
++ + +
+++ ++ ++
++++ ++ ++
+++++++ ++
++++++++++  <--- base layer

Part 2 — Pour water and render final state

Implement dumpWater(heights, waterAmount, column) that simulates pouring waterAmount units of water onto the terrain at index column.

Water movement rules (1 unit at a time)

For each unit of water:

  1. Start at i = column.
  2. The unit first tries to move left to find the closest position with a strictly lower “effective height” (terrain height + already-settled water) by scanning left while the effective height does not increase.
    • More precisely: move left while eff(left) <= eff(current).
    • Track the best (lowest) position reached; if any position has eff < eff(column), settle at the leftmost position among the lowest reached.
  3. If no strictly lower position exists on the left, do the symmetric process on the right.
  4. If neither side has a strictly lower reachable position, the unit settles at column.
  5. Once settled, that position’s water count increases by 1 (so its effective height increases by 1).

After all water is poured, print the final ASCII visualization using:

  • + for terrain blocks
  • W for water blocks (stacked above the terrain)

Example call:

  • dumpWater([5,4,3,2,1,3,4,0,3,4], waterAmount=8, column=1)

Expected output should match the described final state (formatting may vary as long as block positions are correct).

Function signatures

  • renderTerrain(heights) -> void
  • dumpWater(heights, waterAmount, column) -> void (may return the final water distribution and/or print the final rendering)

Constraints (assume)

  • 1 <= len(heights) <= 10^4
  • 0 <= heights[i] <= 10^5
  • 0 <= column < len(heights)
  • 0 <= waterAmount <= 10^5

Your solution should be correct and reasonably efficient for the above constraints.

Part 1: Render a 1D Terrain as ASCII

You are given a 1D terrain represented by a list of non-negative integers heights, where heights[i] is the number of terrain blocks stacked above column i.

Return an ASCII rendering of the terrain from top to bottom.

Rendering rules:

  • Use '+' for terrain blocks.
  • Use '.' for empty space (this makes the output unambiguous for automated testing).
  • There is always one extra base row at the bottom made entirely of '+' characters.
  • The base row is not included in heights[i]; it is added separately.
  • All returned rows must have the same length, equal to len(heights).
  • If heights is empty, return an empty list.

Example:

  • heights = [1, 0, 2]
  • Return ["..+", "+.+", "+++"]

Constraints

  • 0 <= len(heights) <= 200
  • 0 <= heights[i] <= 200
  • The total rendered output size will be small enough to fit in memory

Hints

  1. Build the picture one row at a time, starting from the maximum terrain height down to 1.
  2. For a given row level L, column i contains '+' if heights[i] >= L; otherwise it contains '.'.

Part 2: Pour Water on a 1D Terrain and Render the Final State

You are given a 1D terrain represented by a list heights, a number of water units waterAmount, and a starting column column.

Simulate pouring water one unit at a time onto the terrain.

Definitions:

  • effective height(i) = heights[i] + water[i]
  • water[i] is how much water has already settled at column i

For each unit of water:

  1. Start at column.
  2. Try to move left by scanning while the next position does not rise:
    • While effective height(i - 1) <= effective height(i), continue moving left.
    • Among all scanned positions, track the minimum effective height reached.
    • If at least one scanned position is strictly lower than the starting effective height, settle at the leftmost position among the lowest ones reached.
  3. If no strictly lower position exists on the left, do the symmetric process on the right:
    • While effective height(i + 1) <= effective height(i), continue moving right.
    • If at least one scanned position is strictly lower than the starting effective height, settle at the rightmost position among the lowest ones reached.
  4. If neither side has a strictly lower reachable position, the water settles at column.
  5. After settling, that column's water count increases by 1.

After all water is poured, return the final ASCII rendering from top to bottom using:

  • '+' for terrain blocks
  • 'W' for water blocks
  • '.' for empty space
  • one extra full base row of '+' at the bottom

This version returns the rendering instead of printing it.

Constraints

  • 1 <= len(heights) <= 200
  • 0 <= heights[i] <= 100
  • 0 <= waterAmount <= 200
  • 0 <= column < len(heights)
  • The total rendered output size will be small enough to fit in memory

Examples

Example 1

Input: ([2, 1, 2, 1, 2], 1, 2)
Output: ["+W+.+", "+++++", "+++++"]

Explanation: Both sides have a lower reachable column, so the water must prefer the left side first and settle at index 1.

Example 2

Input: ([3, 1, 3], 2, 0)
Output: ["+W+", "+W+", "+++", "+++"]

Explanation: There is no left side, so water falls to the right valley twice, stacking there.

Hints

  1. Keep a separate water array and always compare columns using heights[i] + water[i].
  2. When scanning left or right, stop as soon as the next step would go uphill. While scanning, remember the lowest reachable effective height; on ties, prefer the direction you are scanning toward.