Problem: Where Will the Ball Fall

You have a 2-D `grid` of size `m x n` representing a box, and you have `n`
balls. The box is open on the top and bottom sides.

Each cell in the box has a diagonal board spanning two corners of the cell
that can redirect a ball to the right or to the left.

* A board that redirects the ball to the right spans the top-left corner to the bottom-right corner and is represented in the grid as `1`.
* A board that redirects the ball to the left spans the top-right corner to the bottom-left corner and is represented in the grid as `-1`.

We drop one ball at the top of each column of the box. Each ball can get stuck
in the box or fall out of the bottom. A ball gets stuck if it hits a "V"
shaped pattern between two boards or if a board redirects the ball into either
wall of the box.

Return an array `answer` of size `n` where `answer[i]` is the column that the
ball falls out of at the bottom after dropping the ball from the `ith` column
at the top, or `-1` if the ball gets stuck in the box.


Python solution:
import math
import itertools
import bisect
import collections
import string
import heapq
import functools
import sortedcontainers
from typing import List, Dict, Tuple, Iterator

class Solution:
  def findBall(self, grid: List[List[int]]) -> List[int]:
    m = len(grid)
    n = len(grid[0])
    dp = [i for i in range(n)]
    ans = [-1] * n

    for i in range(m):
      newDp = [-1] * n
      for j in range(n):
        if j + grid[i][j] < 0 or j + grid[i][j] == n:
          continue
        if grid[i][j] == 1 and grid[i][j + 1] == -1 or grid[i][j] == -1 and grid[i][j - 1] == 1:
          continue
        newDp[j + grid[i][j]] = dp[j]
      dp = newDp

    for i, ball in enumerate(dp):
      if ball != -1:
        ans[ball] = i

    return ans


Java solution:
class Solution {
  public int[] findBall(int[][] grid) {
    final int m = grid.length;
    final int n = grid[0].length;
    // dp[i] := status of the i-th column
    // -1 := empty, 0 := b0, 1 := b1, ...
    int[] dp = new int[n];
    // ans[i] := the i-th ball's final position
    int[] ans = new int[n];
    Arrays.fill(ans, -1);

    for (int i = 0; i < n; ++i)
      dp[i] = i;

    for (int i = 0; i < m; ++i) {
      int[] newDp = new int[n];
      Arrays.fill(newDp, -1);
      for (int j = 0; j < n; ++j) {
        // out-of-bounds
        if (j + grid[i][j] < 0 || j + grid[i][j] == n)
          continue;
        // Stuck
        if (grid[i][j] == 1 && grid[i][j + 1] == -1 || grid[i][j] == -1 && grid[i][j - 1] == 1)
          continue;
        newDp[j + grid[i][j]] = dp[j];
      }
      dp = newDp;
    }

    for (int i = 0; i < n; ++i)
      if (dp[i] != -1)
        ans[dp[i]] = i;

    return ans;
  }
}


C++ solution:
class Solution {
 public:
  vector<int> findBall(vector<vector<int>>& grid) {
    const int m = grid.size();
    const int n = grid[0].size();
    // dp[i] := status of the i-th column
    // -1 := empty, 0 := b0, 1 := b1, ...
    vector<int> dp(n);
    // ans[i] := the i-th ball's final position
    vector<int> ans(n, -1);

    iota(dp.begin(), dp.end(), 0);

    for (int i = 0; i < m; ++i) {
      vector<int> newDp(n, -1);
      for (int j = 0; j < n; ++j) {
        // out-of-bounds
        if (j + grid[i][j] < 0 || j + grid[i][j] == n)
          continue;
        // Stuck
        if (grid[i][j] == 1 && grid[i][j + 1] == -1 ||
            grid[i][j] == -1 && grid[i][j - 1] == 1)
          continue;
        newDp[j + grid[i][j]] = dp[j];
      }
      dp = std::move(newDp);
    }

    for (int i = 0; i < n; ++i)
      if (dp[i] != -1)
        ans[dp[i]] = i;

    return ans;
  }
};