Strings `s1` and `s2` are `k`-similar (for some non-negative integer `k`) if
we can swap the positions of two letters in `s1` exactly `k` times so that the
resulting string equals `s2`.

Given two anagrams `s1` and `s2`, return the smallest `k` for which `s1` and
`s2` are `k`-similar.

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 kSimilarity(self, s1: str, s2: str) -> int:
    ans = 0
    q = collections.deque([s1])
    seen = {s1}

    while q:
      for _ in range(len(q)):
        curr = q.popleft()
        if curr == s2:
          return ans
        for child in self._getChildren(curr, s2):
          if child in seen:
            continue
          q.append(child)
          seen.add(child)
      ans += 1

    return -1

  def _getChildren(self, curr: str, target: str) -> List[str]:
    children = []
    s = list(curr)
    i = 0
    while curr[i] == target[i]:
      i += 1

    for j in range(i + 1, len(s)):
      if s[j] == target[i]:
        s[i], s[j] = s[j], s[i]
        children.append(''.join(s))
        s[i], s[j] = s[j], s[i]

    return children

class Solution {
  public int kSimilarity(String s1, String s2) {
    Queue<String> q = new ArrayDeque<>(List.of(s1));
    Set<String> seen = new HashSet<>(Arrays.asList(s1));

    for (int step = 0; !q.isEmpty(); ++step)
      for (int sz = q.size(); sz > 0; --sz) {
        final String curr = q.poll();
        if (curr.equals(s2))
          return step;
        for (final String child : getChildren(curr, s2)) {
          if (seen.contains(child))
            continue;
          q.offer(child);
          seen.add(child);
        }
      }

    return -1;
  }

  private List<String> getChildren(final String curr, final String target) {
    List<String> children = new ArrayList<>();
    char[] charArray = curr.toCharArray();
    int i = 0; // the first index s.t. curr.charAt(i) != target.charAt(i)
    while (curr.charAt(i) == target.charAt(i))
      ++i;

    for (int j = i + 1; j < charArray.length; ++j)
      if (curr.charAt(j) == target.charAt(i)) {
        swap(charArray, i, j);
        children.add(String.valueOf(charArray));
        swap(charArray, i, j);
      }

    return children;
  }

  private void swap(char[] charArray, int i, int j) {
    final char temp = charArray[i];
    charArray[i] = charArray[j];
    charArray[j] = temp;
  }
}

class Solution {
 public:
  int kSimilarity(string s1, string s2) {
    queue<string> q{{s1}};
    unordered_set<string> seen{{s1}};

    for (int step = 0; !q.empty(); ++step)
      for (int sz = q.size(); sz > 0; --sz) {
        string curr = q.front();
        q.pop();
        if (curr == s2)
          return step;
        for (const string& child : getChildren(curr, s2)) {
          if (seen.contains(child))
            continue;
          q.push(child);
          seen.insert(child);
        }
      }

    return -1;
  }

 private:
  vector<string> getChildren(string& curr, const string& target) {
    vector<string> children;
    int i = 0;  // the first index s.t. curr[i] != target[i]
    while (curr[i] == target[i])
      ++i;

    for (int j = i + 1; j < curr.length(); ++j)
      if (curr[j] == target[i]) {
        swap(curr[i], curr[j]);
        children.push_back(curr);
        swap(curr[i], curr[j]);
      }

    return children;
  }
};


You are given an `m x n` binary matrix `grid`.

A move consists of choosing any row or column and toggling each value in that
row or column (i.e., changing all `0`'s to `1`'s, and all `1`'s to `0`'s).

Every row of the matrix is interpreted as a binary number, and the score of
the matrix is the sum of these numbers.

Return the highest possible score after making any number of moves (including
zero moves).

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 matrixScore(self, grid: List[List[int]]) -> int:
    for row in grid:
      if row[0] == 0:
        self._flip(row)

    for j, col in enumerate(list(zip(*grid))):
      if sum(col) * 2 < len(grid):
        self._flipCol(grid, j)

    return sum(self._binary(row) for row in grid)

  def _flip(self, row: List[int]) -> None:
    for i in range(len(row)):
      row[i] ^= 1

  def _flipCol(self, grid: List[List[int]], j: int) -> None:
    for i in range(len(grid)):
      grid[i][j] ^= 1

  def _binary(self, row: List[int]) -> int:
    res = row[0]
    for j in range(1, len(row)):
      res = res * 2 + row[j]
    return res

class Solution {
  public int matrixScore(int[][] grid) {
    final int m = grid.length;
    final int n = grid[0].length;
    int ans = 0;

    // Flip the rows with a leading 0.
    for (int[] row : grid)
      if (row[0] == 0)
        flip(row);

    // Flip the columns with 1s < 0s.
    for (int j = 0; j < n; ++j)
      if (onesColCount(grid, j) * 2 < m)
        flipCol(grid, j);

    // Add a binary number for each row.
    for (int[] row : grid)
      ans += binary(row);

    return ans;
  }

  private void flip(int[] row) {
    for (int i = 0; i < row.length; ++i)
      row[i] ^= 1;
  }

  private int onesColCount(int[][] grid, int j) {
    int ones = 0;
    for (int i = 0; i < grid.length; ++i)
      ones += grid[i][j];
    return ones;
  }

  private void flipCol(int[][] grid, int j) {
    for (int i = 0; i < grid.length; ++i)
      grid[i][j] ^= 1;
  }

  private int binary(int[] row) {
    int res = row[0];
    for (int j = 1; j < row.length; ++j)
      res = res * 2 + row[j];
    return res;
  }
}

class Solution {
 public:
  int matrixScore(vector<vector<int>>& grid) {
    const int m = grid.size();
    const int n = grid[0].size();
    int ans = 0;

    // Flip the rows with a leading 0.
    for (auto& row : grid)
      if (row[0] == 0)
        flip(row);

    // Flip the columns with 1s < 0s.
    for (int j = 0; j < n; ++j)
      if (onesColCount(grid, j) * 2 < m)
        flipCol(grid, j);

    // Add a binary number for each row.
    for (const vector<int>& row : grid)
      ans += binary(row);

    return ans;
  }

 private:
  void flip(vector<int>& row) {
    for (int i = 0; i < row.size(); ++i)
      row[i] ^= 1;
  }

  int onesColCount(const vector<vector<int>>& grid, int j) {
    int ones = 0;
    for (int i = 0; i < grid.size(); ++i)
      ones += grid[i][j];
    return ones;
  }

  void flipCol(vector<vector<int>>& grid, int j) {
    for (int i = 0; i < grid.size(); ++i)
      grid[i][j] ^= 1;
  }

  int binary(const vector<int>& row) {
    int res = row[0];
    for (int j = 1; j < row.size(); ++j)
      res = res * 2 + row[j];
    return res;
  }
};


Given an integer n, return the smallest prime palindrome greater than or equal
to `n`.

An integer is prime if it has exactly two divisors: `1` and itself. Note that
`1` is not a prime number.

* For example, `2`, `3`, `5`, `7`, `11`, and `13` are all primes.

An integer is a palindrome if it reads the same from left to right as it does
from right to left.

* For example, `101` and `12321` are palindromes.

The test cases are generated so that the answer always exists and is in the
range `[2, 2 * 108]`.

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 primePalindrome(self, n: int) -> int:
    def getPalindromes(n: int):
      length = n // 2
      for i in range(10**(length - 1), 10**length):
        s = str(i)
        for j in range(10):
          yield int(s + str(j) + s[::-1])

    def isPrime(num: int) -> bool:
      for i in range(2, int(num**0.5 + 1)):
        if num % i == 0:
          return False
      return True

    if n <= 2:
      return 2
    if n == 3:
      return 3
    if n <= 5:
      return 5
    if n <= 7:
      return 7
    if n <= 11:
      return 11

    nLength = len(str(n))

    while True:
      for num in getPalindromes(nLength):
        if num >= n and isPrime(num):
          return num
      nLength += 1

class Solution {
  public int primePalindrome(int n) {
    if (n <= 2)
      return 2;
    if (n == 3)
      return 3;
    if (n <= 5)
      return 5;
    if (n <= 7)
      return 7;
    if (n <= 11)
      return 11;

    int nLength = String.valueOf(n).length();

    while (true) {
      for (final int num : getPalindromes(nLength))
        if (num >= n && isPrime(num))
          return num;
      ++nLength;
    }
  }

  private List<Integer> getPalindromes(int n) {
    List<Integer> palindromes = new ArrayList<>();
    int length = n / 2;

    for (int i = (int) Math.pow(10, length - 1); i < (int) Math.pow(10, length); ++i) {
      String s = String.valueOf(i);
      String reversedS = new StringBuilder(s).reverse().toString();
      for (int j = 0; j < 10; ++j)
        palindromes.add(Integer.valueOf(s + String.valueOf(j) + reversedS));
    }

    return palindromes;
  }

  private boolean isPrime(int num) {
    for (int i = 2; i < (int) Math.sqrt(num) + 1; ++i)
      if (num % i == 0)
        return false;
    return true;
  }
}

class Solution {
 public:
  int primePalindrome(int n) {
    if (n <= 2)
      return 2;
    if (n == 3)
      return 3;
    if (n <= 5)
      return 5;
    if (n <= 7)
      return 7;
    if (n <= 11)
      return 11;

    int nLength = to_string(n).length();

    while (true) {
      for (const int num : getPalindromes(nLength))
        if (num >= n && isPrime(num))
          return num;
      ++nLength;
    }

    throw;
  }

 private:
  vector<int> getPalindromes(int n) {
    vector<int> palindromes;
    const int length = n / 2;

    for (int i = pow(10, length - 1); i < pow(10, length); ++i) {
      const string s = to_string(i);
      string reversedS = s;
      ranges::reverse(reversedS);
      for (int j = 0; j < 10; ++j)
        palindromes.push_back(stoi(s + to_string(j) + reversedS));
    }

    return palindromes;
  }

  bool isPrime(int num) {
    for (int i = 2; i < sqrt(num) + 1; ++i)
      if (num % i == 0)
        return false;
    return true;
  }
};


You are given an undirected graph (the "original graph") with `n` nodes
labeled from `0` to `n - 1`. You decide to subdivide each edge in the graph
into a chain of nodes, with the number of new nodes varying between each edge.

The graph is given as a 2D array of `edges` where `edges[i] = [ui, vi, cnti]`
indicates that there is an edge between nodes `ui` and `vi` in the original
graph, and `cnti` is the total number of new nodes that you will subdivide the
edge into. Note that `cnti == 0` means you will not subdivide the edge.

To subdivide the edge `[ui, vi]`, replace it with `(cnti + 1)` new edges and
`cnti` new nodes. The new nodes are `x1`, `x2`, ..., `xcnti`, and the new
edges are `[ui, x1]`, `[x1, x2]`, `[x2, x3]`, ..., `[xcnti-1, xcnti]`,
`[xcnti, vi]`.

In this new graph, you want to know how many nodes are reachable from the node
`0`, where a node is reachable if the distance is `maxMoves` or less.

Given the original graph and `maxMoves`, return the number of nodes that are
reachable from node `0` in the new graph.

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 reachableNodes(self, edges: List[List[int]], maxMoves: int, n: int) -> int:
    graph = [[] for _ in range(n)]
    dist = [maxMoves + 1] * n

    for u, v, cnt in edges:
      graph[u].append((v, cnt))
      graph[v].append((u, cnt))

    reachableNodes = self._dijkstra(graph, 0, maxMoves, dist)
    reachableSubnodes = 0

    for u, v, cnt in edges:
      a = 0 if dist[u] > maxMoves else min(maxMoves - dist[u], cnt)
      b = 0 if dist[v] > maxMoves else min(maxMoves - dist[v], cnt)
      reachableSubnodes += min(a + b, cnt)

    return reachableNodes + reachableSubnodes

  def _dijkstra(self, graph: List[List[Tuple[int, int]]], src: int, maxMoves: int, dist: List[int]) -> int:
    dist[src] = 0
    minHeap = [(dist[src], src)]

    while minHeap:
      d, u = heapq.heappop(minHeap)
      if dist[u] >= maxMoves:
        break
      if d > dist[u]:
        continue
      for v, w in graph[u]:
        newDist = d + w + 1
        if newDist < dist[v]:
          dist[v] = newDist
          heapq.heappush(minHeap, (newDist, v))

    return sum(d <= maxMoves for d in dist)

class Solution {
  public int reachableNodes(int[][] edges, int maxMoves, int n) {
    List<Pair<Integer, Integer>>[] graph = new List[n];
    int[] dist = new int[n];
    Arrays.fill(dist, maxMoves + 1);
    Arrays.setAll(graph, i -> new ArrayList<>());

    for (int[] edge : edges) {
      final int u = edge[0];
      final int v = edge[1];
      final int cnt = edge[2];
      graph[u].add(new Pair<>(v, cnt));
      graph[v].add(new Pair<>(u, cnt));
    }

    final int reachableNodes = dijkstra(graph, 0, maxMoves, dist);
    int reachableSubnodes = 0;

    for (int[] edge : edges) {
      final int u = edge[0];
      final int v = edge[1];
      final int cnt = edge[2];
      // the number of reachable nodes of `edge` from `u`
      final int a = dist[u] > maxMoves ? 0 : Math.min(maxMoves - dist[u], cnt);
      // the number of reachable nodes of `edge` from `v`
      final int b = dist[v] > maxMoves ? 0 : Math.min(maxMoves - dist[v], cnt);
      reachableSubnodes += Math.min(a + b, cnt);
    }

    return reachableNodes + reachableSubnodes;
  }

  private int dijkstra(List<Pair<Integer, Integer>>[] graph, int src, int maxMoves, int[] dist) {
    dist[src] = 0;
    Queue<Pair<Integer, Integer>> minHeap =
        new PriorityQueue<>(Comparator.comparingInt(Pair::getKey)) {
          { offer(new Pair<>(dist[src], src)); } // (d, u)
        };

    while (!minHeap.isEmpty()) {
      final int d = minHeap.peek().getKey();
      final int u = minHeap.poll().getValue();
      // Already took `maxMoves` to reach `u`, so can't explore anymore.
      if (d >= maxMoves)
        break;
      if (d > dist[u])
        continue;
      for (Pair<Integer, Integer> pair : graph[u]) {
        final int v = pair.getKey();
        final int w = pair.getValue();
        if (d + w + 1 < dist[v]) {
          dist[v] = d + w + 1;
          minHeap.offer(new Pair<>(dist[v], v));
        }
      }
    }

    return (int) Arrays.stream(dist).filter(d -> d <= maxMoves).count();
  }
}

class Solution {
 public:
  int reachableNodes(vector<vector<int>>& edges, int maxMoves, int n) {
    vector<vector<pair<int, int>>> graph(n);
    vector<int> dist(graph.size(), maxMoves + 1);

    for (const vector<int>& edge : edges) {
      const int u = edge[0];
      const int v = edge[1];
      const int cnt = edge[2];
      graph[u].emplace_back(v, cnt);
      graph[v].emplace_back(u, cnt);
    }

    const int reachableNodes = dijkstra(graph, 0, maxMoves, dist);
    int reachableSubnodes = 0;

    for (const vector<int>& edge : edges) {
      const int u = edge[0];
      const int v = edge[1];
      const int cnt = edge[2];
      // the number of reachable nodes of `edge` from `u`
      const int a = dist[u] > maxMoves ? 0 : min(maxMoves - dist[u], cnt);
      // the number of reachable nodes of `edge` from `v`
      const int b = dist[v] > maxMoves ? 0 : min(maxMoves - dist[v], cnt);
      reachableSubnodes += min(a + b, cnt);
    }

    return reachableNodes + reachableSubnodes;
  }

 private:
  int dijkstra(const vector<vector<pair<int, int>>>& graph, int src,
               int maxMoves, vector<int>& dist) {
    dist[src] = 0;
    using P = pair<int, int>;  // (d, u)
    priority_queue<P, vector<P>, greater<>> minHeap;
    minHeap.emplace(dist[src], src);

    while (!minHeap.empty()) {
      const auto [d, u] = minHeap.top();
      minHeap.pop();
      // Already took `maxMoves` to reach `u`, so can't explore anymore.
      if (d >= maxMoves)
        break;
      if (d > dist[u])
        continue;
      for (const auto& [v, w] : graph[u])
        if (d + w + 1 < dist[v]) {
          dist[v] = d + w + 1;
          minHeap.emplace(dist[v], v);
        }
    }

    return ranges::count_if(dist, [&](int d) { return d <= maxMoves; });
  }
};


You are given an `n x n` integer matrix `board` where the cells are labeled
from `1` to `n2` in a Boustrophedon style starting from the bottom left of the
board (i.e. `board[n - 1][0]`) and alternating direction each row.

You start on square `1` of the board. In each move, starting from square
`curr`, do the following:

* Choose a destination square `next` with a label in the range `[curr + 1, min(curr + 6, n2)]`.
* This choice simulates the result of a standard 6-sided die roll: i.e., there are always at most 6 destinations, regardless of the size of the board.
* If `next` has a snake or ladder, you must move to the destination of that snake or ladder. Otherwise, you move to `next`.
* The game ends when you reach the square `n2`.

A board square on row `r` and column `c` has a snake or ladder if `board[r][c]
!= -1`. The destination of that snake or ladder is `board[r][c]`. Squares `1`
and `n2` do not have a snake or ladder.

Note that you only take a snake or ladder at most once per move. If the
destination to a snake or ladder is the start of another snake or ladder, you
do not follow the subsequent snake or ladder.

* For example, suppose the board is `[[-1,4],[-1,3]]`, and on the first move, your destination square is `2`. You follow the ladder to square `3`, but do not follow the subsequent ladder to `4`.

Return the least number of moves required to reach the square `n2`. If it is
not possible to reach the square, return `-1`.

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 snakesAndLadders(self, board: List[List[int]]) -> int:
    n = len(board)
    ans = 0
    q = collections.deque([1])
    seen = set()
    A = [0] * (1 + n * n)

    for i in range(n):
      for j in range(n):
        if n - i & 1 :
          A[(n - 1 - i) * n + (j + 1)] = board[i][j]
        else:
          A[(n - 1 - i) * n + (n - j)] = board[i][j]

    while q:
      ans += 1
      for _ in range(len(q)):
        curr = q.popleft()
        for next in range(curr + 1, min(curr + 6, n * n) + 1):
          dest = A[next] if A[next] > 0 else next
          if dest == n * n:
            return ans
          if dest in seen:
            continue
          q.append(dest)
          seen.add(dest)

    return -1

class Solution {
  public int snakesAndLadders(int[][] board) {
    final int n = board.length;
    Queue<Integer> q = new ArrayDeque<>(List.of(1));
    boolean[] seen = new boolean[1 + n * n];
    int[] arr = new int[1 + n * n]; // 2D -> 1D

    for (int i = 0; i < n; ++i)
      for (int j = 0; j < n; ++j)
        arr[(n - 1 - i) * n + ((n - i) % 2 == 0 ? n - j : j + 1)] = board[i][j];

    for (int step = 1; !q.isEmpty(); ++step)
      for (int sz = q.size(); sz > 0; --sz) {
        final int curr = q.poll();
        for (int next = curr + 1; next <= Math.min(curr + 6, n * n); ++next) {
          final int dest = arr[next] > 0 ? arr[next] : next;
          if (dest == n * n)
            return step;
          if (seen[dest])
            continue;
          q.offer(dest);
          seen[dest] = true;
        }
      }

    return -1;
  }
}

class Solution {
 public:
  int snakesAndLadders(vector<vector<int>>& board) {
    const int n = board.size();
    queue<int> q{{1}};
    vector<bool> seen(1 + n * n);
    vector<int> arr(1 + n * n);  // 2D -> 1D

    for (int i = 0; i < n; ++i)
      for (int j = 0; j < n; ++j)
        arr[(n - 1 - i) * n + ((n - i) % 2 == 0 ? n - j : j + 1)] = board[i][j];

    for (int step = 1; !q.empty(); ++step)
      for (int sz = q.size(); sz > 0; --sz) {
        const int curr = q.front();
        q.pop();
        for (int next = curr + 1; next <= min(curr + 6, n * n); ++next) {
          const int dest = arr[next] > 0 ? arr[next] : next;
          if (dest == n * n)
            return step;
          if (seen[dest])
            continue;
          q.push(dest);
          seen[dest] = true;
        }
      }

    return -1;
  }
};


A game on an undirected graph is played by two players, Mouse and Cat, who
alternate turns.

The graph is given as follows: `graph[a]` is a list of all nodes `b` such that
`ab` is an edge of the graph.

The mouse starts at node `1` and goes first, the cat starts at node `2` and
goes second, and there is a hole at node `0`.

During each player's turn, they must travel along one edge of the graph that
meets where they are. For example, if the Mouse is at node 1, it must travel
to any node in `graph[1]`.

Additionally, it is not allowed for the Cat to travel to the Hole (node `0`).

Then, the game can end in three ways:

* If ever the Cat occupies the same node as the Mouse, the Cat wins.
* If ever the Mouse reaches the Hole, the Mouse wins.
* If ever a position is repeated (i.e., the players are in the same position as a previous turn, and it is the same player's turn to move), the game is a draw.

Given a `graph`, and assuming both players play optimally, return

* `1` if the mouse wins the game,
* `2` if the cat wins the game, or
* `0` if the game is a draw.

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

from enum import IntEnum

class State(IntEnum):
  kDraw = 0
  kMouseWin = 1
  kCatWin = 2

class Solution:
  def catMouseGame(self, graph: List[List[int]]) -> int:
    n = len(graph)
    states = [[[0] * 2 for i in range(n)] for j in range(n)]
    outDegree = [[[0] * 2 for i in range(n)] for j in range(n)]
    q = collections.deque()

    for cat in range(n):
      for mouse in range(n):
        outDegree[cat][mouse][0] = len(graph[mouse])
        outDegree[cat][mouse][1] = len(graph[cat]) - graph[cat].count(0)

    for cat in range(1, n):
      for move in range(2):
        states[cat][0][move] = int(State.kMouseWin)
        q.append((cat, 0, move, int(State.kMouseWin)))
        states[cat][cat][move] = int(State.kCatWin)
        q.append((cat, cat, move, int(State.kCatWin)))

    while q:
      cat, mouse, move, state = q.popleft()
      if cat == 2 and mouse == 1 and move == 0:
        return state
      prevMove = move ^ 1
      for prev in graph[cat if prevMove else mouse]:
        prevCat = prev if prevMove else cat
        if prevCat == 0:
          continue
        prevMouse = mouse if prevMove else prev
        if states[prevCat][prevMouse][prevMove]:
          continue
        if prevMove == 0 and state == int(State.kMouseWin) or \
                prevMove == 1 and state == int(State.kCatWin):
          states[prevCat][prevMouse][prevMove] = state
          q.append((prevCat, prevMouse, prevMove, state))
        else:
          outDegree[prevCat][prevMouse][prevMove] -= 1
          if outDegree[prevCat][prevMouse][prevMove] == 0:
            states[prevCat][prevMouse][prevMove] = state
            q.append((prevCat, prevMouse, prevMove, state))

    return states[2][1][0]

enum State { DRAW, MOUSE_WIN, CAT_WIN }

class Solution {
  public int catMouseGame(int[][] graph) {
    final int n = graph.length;
    // result of (cat, mouse, move)
    // move := 0 (mouse) / 1 (cat)
    int[][][] states = new int[n][n][2];
    int[][][] outDegree = new int[n][n][2];
    Queue<int[]> q = new ArrayDeque<>();

    for (int cat = 0; cat < n; ++cat)
      for (int mouse = 0; mouse < n; ++mouse) {
        outDegree[cat][mouse][0] = graph[mouse].length;
        outDegree[cat][mouse][1] =
            graph[cat].length - (Arrays.stream(graph[cat]).anyMatch(v -> v == 0) ? 1 : 0);
      }

    // Start from the states s.t. the winner can be determined.
    for (int cat = 1; cat < n; ++cat)
      for (int move = 0; move < 2; ++move) {
        // Mouse is in the hole.
        states[cat][0][move] = State.MOUSE_WIN.ordinal();
        q.offer(new int[] {cat, 0, move, State.MOUSE_WIN.ordinal()});
        // Cat catches mouse.
        states[cat][cat][move] = State.CAT_WIN.ordinal();
        q.offer(new int[] {cat, cat, move, State.CAT_WIN.ordinal()});
      }

    while (!q.isEmpty()) {
      final int cat = q.peek()[0];
      final int mouse = q.peek()[1];
      final int move = q.peek()[2];
      final int state = q.poll()[3];
      if (cat == 2 && mouse == 1 && move == 0)
        return state;
      final int prevMove = move ^ 1;
      for (final int prev : graph[prevMove == 0 ? mouse : cat]) {
        final int prevCat = prevMove == 0 ? cat : prev;
        if (prevCat == 0) // invalid
          continue;
        final int prevMouse = prevMove == 0 ? prev : mouse;
        // The state has been determined.
        if (states[prevCat][prevMouse][prevMove] > 0)
          continue;
        if (prevMove == 0 && state == State.MOUSE_WIN.ordinal() ||
            prevMove == 1 && state == State.CAT_WIN.ordinal() ||
            --outDegree[prevCat][prevMouse][prevMove] == 0) {
          states[prevCat][prevMouse][prevMove] = state;
          q.offer(new int[] {prevCat, prevMouse, prevMove, state});
        }
      }
    }

    return states[2][1][0];
  }
}

enum class State { kDraw, kMouseWin, kCatWin };

class Solution {
 public:
  int catMouseGame(vector<vector<int>>& graph) {
    const int n = graph.size();
    // result of (cat, mouse, move)
    // move := 0 (mouse) / 1 (cat)
    vector<vector<vector<State>>> states(
        n, vector<vector<State>>(n, vector<State>(2)));
    vector<vector<vector<int>>> outDegree(
        n, vector<vector<int>>(n, vector<int>(2)));
    queue<tuple<int, int, int, State>> q;  // (cat, mouse, move, state)

    for (int cat = 0; cat < n; ++cat)
      for (int mouse = 0; mouse < n; ++mouse) {
        outDegree[cat][mouse][0] = graph[mouse].size();
        outDegree[cat][mouse][1] =
            graph[cat].size() - ranges::count(graph[cat], 0);
      }

    // Start from the states s.t. the winner can be determined.
    for (int cat = 1; cat < n; ++cat)
      for (int move = 0; move < 2; ++move) {
        // Mouse is in the hole.
        states[cat][0][move] = State::kMouseWin;
        q.emplace(cat, 0, move, State::kMouseWin);
        // Cat catches mouse.
        states[cat][cat][move] = State::kCatWin;
        q.emplace(cat, cat, move, State::kCatWin);
      }

    while (!q.empty()) {
      const auto [cat, mouse, move, state] = q.front();
      q.pop();
      if (cat == 2 && mouse == 1 && move == 0)
        return static_cast<int>(state);
      const int prevMove = move ^ 1;
      for (const int prev : graph[prevMove ? cat : mouse]) {
        const int prevCat = prevMove ? prev : cat;
        if (prevCat == 0)  // invalid
          continue;
        const int prevMouse = prevMove ? mouse : prev;
        // The state has been determined.
        if (states[prevCat][prevMouse][prevMove] != State::kDraw)
          continue;
        if (prevMove == 0 && state == State::kMouseWin ||
            prevMove == 1 && state == State::kCatWin ||
            --outDegree[prevCat][prevMouse][prevMove] == 0) {
          states[prevCat][prevMouse][prevMove] = state;
          q.emplace(prevCat, prevMouse, prevMove, state);
        }
      }
    }

    return static_cast<int>(states[2][1][0]);
  }
};


Given an integer array `arr`, and an integer `target`, return the number of
tuples `i, j, k` such that `i < j < k` and `arr[i] + arr[j] + arr[k] ==
target`.

As the answer can be very large, return it modulo `109 + 7`.

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 threeSumMulti(self, arr: List[int], target: int) -> int:
    kMod = 1_000_000_007
    ans = 0
    count = collections.Counter(arr)

    for i, x in count.items():
      for j, y in count.items():
        k = target - i - j
        if k not in count:
          continue
        if i == j and j == k:
          ans = (ans + x * (x - 1) * (x - 2) // 6) % kMod
        elif i == j and j != k:
          ans = (ans + x * (x - 1) // 2 * count[k]) % kMod
        elif i < j and j < k:
          ans = (ans + x * y * count[k]) % kMod

    return ans % kMod

class Solution {
  public int threeSumMulti(int[] arr, int target) {
    final int MOD = 1_000_000_007;
    int ans = 0;
    Map<Integer, Integer> count = new HashMap<>();

    for (final int a : arr)
      count.merge(a, 1, Integer::sum);

    for (Map.Entry<Integer, Integer> entry : count.entrySet()) {
      final int i = entry.getKey();
      final int x = entry.getValue();
      for (Map.Entry<Integer, Integer> entry2 : count.entrySet()) {
        final int j = entry2.getKey();
        final int y = entry2.getValue();
        final int k = target - i - j;
        if (!count.containsKey(k))
          continue;
        if (i == j && j == k)
          ans = (int) ((ans + (long) x * (x - 1) * (x - 2) / 6) % MOD);
        else if (i == j && j != k)
          ans = (int) ((ans + (long) x * (x - 1) / 2 * count.get(k)) % MOD);
        else if (i < j && j < k)
          ans = (int) ((ans + (long) x * y * count.get(k)) % MOD);
      }
    }

    return ans;
  }
}

class Solution {
 public:
  int threeSumMulti(vector<int>& arr, int target) {
    constexpr int kMod = 1'000'000'007;
    int ans = 0;
    unordered_map<int, int> count;

    for (const int a : arr)
      ++count[a];

    for (const auto& [i, x] : count)
      for (const auto& [j, y] : count) {
        const int k = target - i - j;
        const auto it = count.find(k);
        if (it == count.cend())
          continue;
        if (i == j && j == k)
          ans = (ans + static_cast<long>(x) * (x - 1) * (x - 2) / 6) % kMod;
        else if (i == j && j != k)
          ans = (ans + static_cast<long>(x) * (x - 1) / 2 * it->second) % kMod;
        else if (i < j && j < k)
          ans = (ans + static_cast<long>(x) * y * it->second) % kMod;
      }

    return ans;
  }
};


You are given an array `arr` which consists of only zeros and ones, divide the
array into three non-empty parts such that all of these parts represent the
same binary value.

If it is possible, return any `[i, j]` with `i + 1 < j`, such that:

* `arr[0], arr[1], ..., arr[i]` is the first part,
* `arr[i + 1], arr[i + 2], ..., arr[j - 1]` is the second part, and
* `arr[j], arr[j + 1], ..., arr[arr.length - 1]` is the third part.
* All three parts have equal binary values.

If it is not possible, return `[-1, -1]`.

Note that the entire part is used when considering what binary value it
represents. For example, `[1,1,0]` represents `6` in decimal, not `3`. Also,
leading zeros are allowed, so `[0,1,1]` and `[1,1]` represent the same value.

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 threeEqualParts(self, arr: List[int]) -> List[int]:
    ones = sum(a == 1 for a in arr)

    if ones == 0:
      return [0, len(arr) - 1]
    if ones % 3 != 0:
      return [-1, -1]

    k = ones // 3
    i = 0

    for i in range(len(arr)):
      if arr[i] == 1:
        first = i
        break

    gapOnes = k

    for j in range(i + 1, len(arr)):
      if arr[j] == 1:
        gapOnes -= 1
        if gapOnes == 0:
          second = j
          break

    gapOnes = k

    for i in range(j + 1, len(arr)):
      if arr[i] == 1:
        gapOnes -= 1
        if gapOnes == 0:
          third = i
          break

    while third < len(arr) and arr[first] == arr[second] == arr[third]:
      first += 1
      second += 1
      third += 1

    if third == len(arr):
      return [first - 1, second]
    return [-1, -1]

class Solution {
  public int[] threeEqualParts(int[] arr) {
    int ones = 0;

    for (final int a : arr)
      if (a == 1)
        ++ones;

    if (ones == 0)
      return new int[] {0, arr.length - 1};
    if (ones % 3 != 0)
      return new int[] {-1, -1};

    int k = ones / 3;
    int i = 0;
    int j = 0;
    int first = 0;
    int second = 0;
    int third = 0;

    for (i = 0; i < arr.length; ++i)
      if (arr[i] == 1) {
        first = i;
        break;
      }

    int gapOnes = k;

    for (j = i + 1; j < arr.length; ++j)
      if (arr[j] == 1 && --gapOnes == 0) {
        second = j;
        break;
      }

    gapOnes = k;

    for (i = j + 1; i < arr.length; ++i)
      if (arr[i] == 1 && --gapOnes == 0) {
        third = i;
        break;
      }

    while (third < arr.length && arr[first] == arr[second] && arr[second] == arr[third]) {
      ++first;
      ++second;
      ++third;
    }

    if (third == arr.length)
      return new int[] {first - 1, second};
    return new int[] {-1, -1};
  }
}

class Solution {
 public:
  vector<int> threeEqualParts(vector<int>& arr) {
    const int ones = ranges::count_if(arr, [](int a) { return a == 1; });

    if (ones == 0)
      return {0, static_cast<int>(arr.size()) - 1};
    if (ones % 3 != 0)
      return {-1, -1};

    int k = ones / 3;
    int i;
    int j;
    int first;
    int second;
    int third;

    for (i = 0; i < arr.size(); ++i)
      if (arr[i] == 1) {
        first = i;
        break;
      }

    int gapOnes = k;

    for (j = i + 1; j < arr.size(); ++j)
      if (arr[j] == 1 && --gapOnes == 0) {
        second = j;
        break;
      }

    gapOnes = k;

    for (i = j + 1; i < arr.size(); ++i)
      if (arr[i] == 1 && --gapOnes == 0) {
        third = i;
        break;
      }

    while (third < arr.size() && arr[first] == arr[second] &&
           arr[second] == arr[third]) {
      ++first;
      ++second;
      ++third;
    }

    if (third == arr.size())
      return {first - 1, second};
    return {-1, -1};
  }
};


The chess knight has a unique movement, it may move two squares vertically and
one square horizontally, or two squares horizontally and one square vertically
(with both forming the shape of an L). The possible movements of chess knight
are shown in this diagram:

A chess knight can move as indicated in the chess diagram below:

We have a chess knight and a phone pad as shown below, the knight can only
stand on a numeric cell (i.e. blue cell).

Given an integer `n`, return how many distinct phone numbers of length `n` we
can dial.

You are allowed to place the knight on any numeric cell initially and then you
should perform `n - 1` jumps to dial a number of length `n`. All jumps should
be valid knight jumps.

As the answer may be very large, return the answer modulo `109 + 7`.

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 knightDialer(self, n: int) -> int:
    dirs = ((1, 2), (2, 1), (2, -1), (1, -2), (-1, -2), (-2, -1), (-2, 1), (-1, 2))
    kMod = 1_000_000_007

    dp = [[1] * 3 for _ in range(4)]
    dp[3][0] = dp[3][2] = 0

    for _ in range(n - 1):
      newDp = [[0] * 3 for _ in range(4)]
      for i in range(4):
        for j in range(3):
          if (i, j) in ((3, 0), (3, 2)):
            continue
          for dx, dy in dirs:
            x = i + dx
            y = j + dy
            if x < 0 or x >= 4 or y < 0 or y >= 3:
              continue
            if (x, y) in ((3, 0), (3, 2)):
              continue
            newDp[x][y] = (newDp[x][y] + dp[i][j]) % kMod
      dp = newDp

    return sum(map(sum, dp)) % kMod

class Solution {
  public int knightDialer(int n) {
    final int[][] DIRS = {{1, 2}, {2, 1}, {2, -1}, {1, -2}, {-1, -2}, {-2, -1}, {-2, 1}, {-1, 2}};
    final int MOD = 1_000_000_007;
    // dp[i][j] := the number of ways to stand on (i, j)
    int[][] dp = new int[4][3];
    Arrays.stream(dp).forEach(A -> Arrays.fill(A, 1));
    dp[3][0] = dp[3][2] = 0;

    for (int k = 0; k < n - 1; ++k) {
      int[][] newDp = new int[4][3];
      for (int i = 0; i < 4; ++i)
        for (int j = 0; j < 3; ++j) {
          if (isNotNumericCell(i, j))
            continue;
          for (int[] dir : DIRS) {
            final int x = i + dir[0];
            final int y = j + dir[1];
            if (x < 0 || x >= 4 || y < 0 || y >= 3)
              continue;
            if (isNotNumericCell(x, y))
              continue;
            newDp[i][j] = (newDp[i][j] + dp[x][y]) % MOD;
          }
        }
      dp = newDp;
    }

    int ans = 0;

    for (int[] row : dp)
      for (final int a : row)
        ans = (ans + a) % MOD;

    return ans;
  }

  private boolean isNotNumericCell(int i, int j) {
    return i == 3 && (j == 0 || j == 2);
  }
}

class Solution {
 public:
  int knightDialer(int n) {
    constexpr int kDirs[8][2] = {{1, 2},   {2, 1},   {2, -1}, {1, -2},
                                 {-1, -2}, {-2, -1}, {-2, 1}, {-1, 2}};
    constexpr int kMod = 1'000'000'007;

    // dp[i][j] := the number of ways to stand on (i, j)
    vector<vector<int>> dp(4, vector<int>(3, 1));
    dp[3][0] = dp[3][2] = 0;

    for (int k = 0; k < n - 1; ++k) {
      vector<vector<int>> newDp(4, vector<int>(3));
      for (int i = 0; i < 4; ++i)
        for (int j = 0; j < 3; ++j) {
          if (isNotNumericCell(i, j))
            continue;
          for (const auto& [dx, dy] : kDirs) {
            const int x = i + dx;
            const int y = j + dy;
            if (x < 0 || x >= 4 || y < 0 || y >= 3)
              continue;
            if (isNotNumericCell(x, y))
              continue;
            newDp[i][j] = (newDp[i][j] + dp[x][y]) % kMod;
          }
        }
      dp = std::move(newDp);
    }

    int ans = 0;

    for (const vector<int>& row : dp)
      for (const int a : row)
        ans = (ans + a) % kMod;

    return ans;
  }

 private:
  bool isNotNumericCell(int i, int j) {
    return i == 3 && (j == 0 || j == 2);
  }
};


You are given an array of points in the X-Y plane `points` where `points[i] =
[xi, yi]`.

Return the minimum area of a rectangle formed from these points, with sides
parallel to the X and Y axes. If there is not any such rectangle, return `0`.

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 minAreaRect(self, points: List[List[int]]) -> int:
    ans = math.inf
    xToYs = collections.defaultdict(set)

    for x, y in points:
      xToYs[x].add(y)

    for i in range(len(points)):
      for j in range(i):
        x1, y1 = points[i]
        x2, y2 = points[j]
        if x1 == x2 or y1 == y2:
          continue
        if y2 in xToYs[x1] and y1 in xToYs[x2]:
          ans = min(ans, abs(x1 - x2) * abs(y1 - y2))

    return ans if ans < math.inf else 0

class Solution {
  public int minAreaRect(int[][] points) {
    int ans = Integer.MAX_VALUE;
    Map<Integer, Set<Integer>> xToYs = new HashMap<>();

    for (int[] p : points) {
      xToYs.putIfAbsent(p[0], new HashSet<>());
      xToYs.get(p[0]).add(p[1]);
    }

    for (int i = 1; i < points.length; ++i)
      for (int j = 0; j < i; ++j) {
        int[] p = points[i];
        int[] q = points[j];
        if (p[0] == q[0] || p[1] == q[1])
          continue;
        if (xToYs.get(p[0]).contains(q[1]) && xToYs.get(q[0]).contains(p[1]))
          ans = Math.min(ans, Math.abs(p[0] - q[0]) * Math.abs(p[1] - q[1]));
      }

    return ans == Integer.MAX_VALUE ? 0 : ans;
  }
}

class Solution {
 public:
  int minAreaRect(vector<vector<int>>& points) {
    int ans = INT_MAX;
    unordered_map<int, unordered_set<int>> xToYs;

    for (const vector<int>& p : points)
      xToYs[p[0]].insert(p[1]);

    for (int i = 1; i < points.size(); ++i)
      for (int j = 0; j < i; ++j) {
        const vector<int>& p = points[i];
        const vector<int>& q = points[j];
        if (p[0] == q[0] || p[1] == q[1])
          continue;
        if (xToYs[p[0]].contains(q[1]) && xToYs[q[0]].contains(p[1]))
          ans = min(ans, abs(p[0] - q[0]) * abs(p[1] - q[1]));
      }

    return ans == INT_MAX ? 0 : ans;
  }
};


You are given an integer array of unique positive integers `nums`. Consider
the following graph:

* There are `nums.length` nodes, labeled `nums[0]` to `nums[nums.length - 1]`,
* There is an undirected edge between `nums[i]` and `nums[j]` if `nums[i]` and `nums[j]` share a common factor greater than `1`.

Return the size of the largest connected component in the graph.

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

class UnionFind:
  def __init__(self, n: int):
    self.id = list(range(n))
    self.rank = [0] * n

  def unionByRank(self, u: int, v: int) -> None:
    i = self.find(u)
    j = self.find(v)
    if i == j:
      return
    if self.rank[i] < self.rank[j]:
      self.id[i] = j
    elif self.rank[i] > self.rank[j]:
      self.id[j] = i
    else:
      self.id[i] = j
      self.rank[j] += 1

  def find(self, u: int) -> int:
    if self.id[u] != u:
      self.id[u] = self.find(self.id[u])
    return self.id[u]

class Solution:
  def largestComponentSize(self, nums: List[int]) -> int:
    ans = 0
    uf = UnionFind(max(nums) + 1)
    count = collections.Counter()

    for num in nums:
      for x in range(2, int(math.sqrt(num) + 1)):
        if num % x == 0:
          uf.unionByRank(num, x)
          uf.unionByRank(num, num // x)

    for num in nums:
      numRoot = uf.find(num)
      count[numRoot] += 1
      ans = max(ans, count[numRoot])

    return ans

class UnionFind {
  public UnionFind(int n) {
    id = new int[n];
    rank = new int[n];
    for (int i = 0; i < n; ++i)
      id[i] = i;
  }

  public void unionByRank(int u, int v) {
    final int i = find(u);
    final int j = find(v);
    if (i == j)
      return;
    if (rank[i] < rank[j]) {
      id[i] = j;
    } else if (rank[i] > rank[j]) {
      id[j] = i;
    } else {
      id[i] = j;
      ++rank[j];
    }
  }

  public int find(int u) {
    return id[u] == u ? u : (id[u] = find(id[u]));
  }

  private int[] id;
  private int[] rank;
}

class Solution {
  public int largestComponentSize(int[] nums) {
    final int n = Arrays.stream(nums).max().getAsInt();
    int ans = 0;
    UnionFind uf = new UnionFind(n + 1);
    Map<Integer, Integer> count = new HashMap<>();

    for (final int num : nums)
      for (int x = 2; x <= (int) Math.sqrt(num); ++x)
        if (num % x == 0) {
          uf.unionByRank(num, x);
          uf.unionByRank(num, num / x);
        }

    for (final int num : nums)
      ans = Math.max(ans, count.merge(uf.find(num), 1, Integer::sum));

    return ans;
  }
}

class UnionFind {
 public:
  UnionFind(int n) : id(n), rank(n) {
    iota(id.begin(), id.end(), 0);
  }

  void unionByRank(int u, int v) {
    const int i = find(u);
    const int j = find(v);
    if (i == j)
      return;
    if (rank[i] < rank[j]) {
      id[i] = j;
    } else if (rank[i] > rank[j]) {
      id[j] = i;
    } else {
      id[i] = j;
      ++rank[j];
    }
  }

  int find(int u) {
    return id[u] == u ? u : id[u] = find(id[u]);
  }

 private:
  vector<int> id;
  vector<int> rank;
};

class Solution {
 public:
  int largestComponentSize(vector<int>& nums) {
    const int n = ranges::max(nums);
    int ans = 0;
    UnionFind uf(n + 1);
    unordered_map<int, int> count;

    for (const int num : nums)
      for (int x = 2; x <= sqrt(num); ++x)
        if (num % x == 0) {
          uf.unionByRank(num, x);
          uf.unionByRank(num, num / x);
        }

    for (const int num : nums)
      ans = max(ans, ++count[uf.find(num)]);

    return ans;
  }
};


You are given an array of points in the X-Y plane `points` where `points[i] =
[xi, yi]`.

Return the minimum area of any rectangle formed from these points, with sides
not necessarily parallel to the X and Y axes. If there is not any such
rectangle, return `0`.

Answers within `10-5` of the actual answer will be accepted.

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

class Solution:
  def minAreaFreeRect(self, points: List[List[int]]) -> float:
    ans = math.inf
    centerToPoints = collections.defaultdict(list)

    for ax, ay in points:
      for bx, by in points:
        center = ((ax + bx) / 2, (ay + by) / 2)
        centerToPoints[center].append((ax, ay, bx, by))

    def dist(px: int, py: int, qx: int, qy: int) -> float:
      return (px - qx)**2 + (py - qy)**2

    for points in centerToPoints.values():
      for ax, ay, _, _ in points:
        for cx, cy, dx, dy in points:
          if (cx - ax) * (dx - ax) + (cy - ay) * (dy - ay) == 0:
            squaredArea = dist(ax, ay, cx, cy) * dist(ax, ay, dx, dy)
            if squaredArea > 0:
              ans = min(ans, squaredArea)

    return 0 if ans == math.inf else sqrt(ans)

class Solution {
  public double minAreaFreeRect(int[][] points) {
    long ans = Long.MAX_VALUE;
    // For each A, B pair points, {hash(A, B): (ax, ay, bx, by)}.
    Map<Integer, List<int[]>> centerToPoints = new HashMap<>();

    for (int[] A : points)
      for (int[] B : points) {
        int center = hash(A, B);
        if (centerToPoints.get(center) == null)
          centerToPoints.put(center, new ArrayList<>());
        centerToPoints.get(center).add(new int[] {A[0], A[1], B[0], B[1]});
      }

    // For all pair points "that share the same center".
    for (List<int[]> pointPairs : centerToPoints.values())
      for (int[] ab : pointPairs)
        for (int[] cd : pointPairs) {
          final int ax = ab[0], ay = ab[1];
          final int cx = cd[0], cy = cd[1];
          final int dx = cd[2], dy = cd[3];
          // AC is perpendicular to AD.
          // AC dot AD = (cx - ax, cy - ay) dot (dx - ax, dy - ay) == 0.
          if ((cx - ax) * (dx - ax) + (cy - ay) * (dy - ay) == 0) {
            final long squaredArea = dist(ax, ay, cx, cy) * dist(ax, ay, dx, dy);
            if (squaredArea > 0)
              ans = Math.min(ans, squaredArea);
          }
        }

    return ans == Long.MAX_VALUE ? 0 : Math.sqrt(ans);
  }

  private int hash(int[] p, int[] q) {
    return ((p[0] + q[0]) << 16) + (p[1] + q[1]);
  }

  private long dist(long px, long py, long qx, long qy) {
    return (px - qx) * (px - qx) + (py - qy) * (py - qy);
  }
}

class Solution {
 public:
  double minAreaFreeRect(vector<vector<int>>& points) {
    long ans = LONG_MAX;
    // For each A, B pair points, {hash(A, B): (ax, ay, bx, by)}.
    unordered_map<int, vector<tuple<int, int, int, int>>> centerToPoints;

    for (const vector<int>& A : points)
      for (const vector<int>& B : points) {
        const int center = hash(A, B);
        centerToPoints[center].emplace_back(A[0], A[1], B[0], B[1]);
      }

    // For all pair points "that share the same center".
    for (const auto& [_, points] : centerToPoints)
      for (const auto& [ax, ay, bx, by] : points)
        for (const auto& [cx, cy, dx, dy] : points)
          // AC is perpendicular to AD.
          // AC dot AD = (cx - ax, cy - ay) dot (dx - ax, dy - ay) == 0.
          if ((cx - ax) * (dx - ax) + (cy - ay) * (dy - ay) == 0) {
            const long squaredArea =
                dist(ax, ay, cx, cy) * dist(ax, ay, dx, dy);
            if (squaredArea > 0)
              ans = min(ans, squaredArea);
          }

    return ans == LONG_MAX ? 0 : sqrt(ans);
  }

 private:
  int hash(const vector<int>& p, const vector<int>& q) {
    return ((long)(p[0] + q[0]) << 16) + (p[1] + q[1]);
  }

  long dist(int px, int py, int qx, int qy) {
    return (px - qx) * (px - qx) + (py - qy) * (py - qy);
  }
};


You are given an array of strings `equations` that represent relationships
between variables where each string `equations[i]` is of length `4` and takes
one of two different forms: `"xi==yi"` or `"xi!=yi"`.Here, `xi` and `yi` are
lowercase letters (not necessarily different) that represent one-letter
variable names.

Return `true` if it is possible to assign integers to variable names so as to
satisfy all the given equations, or `false` otherwise.

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

class UnionFind:
  def __init__(self, n: int):
    self.id = list(range(n))

  def union(self, u: int, v: int) -> None:
    self.id[self.find(u)] = self.find(v)

  def find(self, u: int) -> int:
    if self.id[u] != u:
      self.id[u] = self.find(self.id[u])
    return self.id[u]

class Solution:
  def equationsPossible(self, equations: List[str]) -> bool:
    uf = UnionFind(26)

    for x, op, _, y in equations:
      if op == '=':
        uf.union(ord(x) - ord('a'), ord(y) - ord('a'))

    for x, op, _, y in equations:
      if op == '!':
        if uf.find(ord(x) - ord('a')) == uf.find(ord(y) - ord('a')):
          return False
    return True

class UnionFind {
  public UnionFind(int n) {
    id = new int[n];
    rank = new int[n];
    for (int i = 0; i < n; ++i)
      id[i] = i;
  }

  public void unionByRank(int u, int v) {
    final int i = find(u);
    final int j = find(v);
    if (i == j)
      return;
    if (rank[i] < rank[j]) {
      id[i] = j;
    } else if (rank[i] > rank[j]) {
      id[j] = i;
    } else {
      id[i] = j;
      ++rank[j];
    }
  }

  public int find(int u) {
    return id[u] == u ? u : (id[u] = find(id[u]));
  }

  private int[] id;
  private int[] rank;
}

class Solution {
  public boolean equationsPossible(String[] equations) {
    UnionFind uf = new UnionFind(26);

    for (final String e : equations)
      if (e.charAt(1) == '=') {
        final int x = e.charAt(0) - 'a';
        final int y = e.charAt(3) - 'a';
        uf.unionByRank(x, y);
      }

    for (final String e : equations)
      if (e.charAt(1) == '!') {
        final int x = e.charAt(0) - 'a';
        final int y = e.charAt(3) - 'a';
        if (uf.find(x) == uf.find(y))
          return false;
      }

    return true;
  }
}

class UnionFind {
 public:
  UnionFind(int n) : id(n) {
    iota(id.begin(), id.end(), 0);
  }

  void union_(int u, int v) {
    id[find(u)] = find(v);
  }

  int find(int u) {
    return id[u] == u ? u : id[u] = find(id[u]);
  }

 private:
  vector<int> id;
};

class Solution {
 public:
  bool equationsPossible(vector<string>& equations) {
    UnionFind uf(26);

    for (const string& e : equations)
      if (e[1] == '=') {
        const int x = e[0] - 'a';
        const int y = e[3] - 'a';
        uf.union_(x, y);
      }

    for (const string& e : equations)
      if (e[1] == '!') {
        const int x = e[0] - 'a';
        const int y = e[3] - 'a';
        if (uf.find(x) == uf.find(y))
          return false;
      }

    return true;
  }
};


On an `8 x 8` chessboard, there is exactly one white rook `'R'` and some
number of white bishops `'B'`, black pawns `'p'`, and empty squares `'.'`.

When the rook moves, it chooses one of four cardinal directions (north, east,
south, or west), then moves in that direction until it chooses to stop,
reaches the edge of the board, captures a black pawn, or is blocked by a white
bishop. A rook is considered attacking a pawn if the rook can capture the pawn
on the rook's turn. The number of available captures for the white rook is the
number of pawns that the rook is attacking.

Return the number of available captures for the white rook.

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 numRookCaptures(self, board: List[List[str]]) -> int:
    ans = 0

    for i in range(8):
      for j in range(8):
        if board[i][j] == 'R':
          i0 = i
          j0 = j

    for d in [[1, 0], [0, 1], [-1, 0], [0, -1]]:
      i = i0 + d[0]
      j = j0 + d[1]
      while 0 <= i < 8 and 0 <= j < 8:
        if board[i][j] == 'p':
          ans += 1
        if board[i][j] != '.':
          break
        i += d[0]
        j += d[1]

    return ans

class Solution {
 public:
  int numRookCaptures(vector<vector<char>>& board) {
    int ans = 0;
    int i0 = 0;
    int j0 = 0;

    for (int i = 0; i < 8; ++i)
      for (int j = 0; j < 8; ++j)
        if (board[i][j] == 'R') {
          i0 = i;
          j0 = j;
        }

    for (const vector<int>& d :
         vector<vector<int>>({{1, 0}, {0, 1}, {-1, 0}, {0, -1}}))
      for (int i = i0 + d[0], j = j0 + d[1]; 0 <= i && i < 8 && 0 <= j && j < 8;
           i += d[0], j += d[1]) {
        if (board[i][j] == 'p')
          ++ans;
        if (board[i][j] != '.')
          break;
      }

    return ans;
  }
};


There is a 2D `grid` of size `n x n` where each cell of this grid has a lamp
that is initially turned off.

You are given a 2D array of lamp positions `lamps`, where `lamps[i] = [rowi,
coli]` indicates that the lamp at `grid[rowi][coli]` is turned on. Even if the
same lamp is listed more than once, it is turned on.

When a lamp is turned on, it illuminates its cell and all other cells in the
same row, column, or diagonal.

You are also given another 2D array `queries`, where `queries[j] = [rowj,
colj]`. For the `jth` query, determine whether `grid[rowj][colj]` is
illuminated or not. After answering the `jth` query, turn off the lamp at
`grid[rowj][colj]` and its 8 adjacent lamps if they exist. A lamp is adjacent
if its cell shares either a side or corner with `grid[rowj][colj]`.

Return an array of integers `ans`, where `ans[j]` should be `1` if the cell in
the `jth` query was illuminated, or `0` if the lamp was not.

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 gridIllumination(self, n: int, lamps: List[List[int]], queries: List[List[int]]) -> List[int]:
    ans = []
    rows = collections.Counter()
    cols = collections.Counter()
    diag1 = collections.Counter()
    diag2 = collections.Counter()
    lampsSet = set()

    for i, j in lamps:
      if (i, j) not in lampsSet:
        lampsSet.add((i, j))
        rows[i] += 1
        cols[j] += 1
        diag1[i + j] += 1
        diag2[i - j] += 1

    for i, j in queries:
      if rows[i] or cols[j] or diag1[i + j] or diag2[i - j]:
        ans.append(1)
        for y in range(max(0, i - 1), min(n, i + 2)):
          for x in range(max(0, j - 1), min(n, j + 2)):
            if (y, x) in lampsSet:
              lampsSet.remove((y, x))
              rows[y] -= 1
              cols[x] -= 1
              diag1[y + x] -= 1
              diag2[y - x] -= 1
      else:
        ans.append(0)

    return ans

class Solution {
  public int[] gridIllumination(int n, int[][] lamps, int[][] queries) {
    List<Integer> ans = new ArrayList<>();
    Map<Integer, Integer> rows = new HashMap<>();
    Map<Integer, Integer> cols = new HashMap<>();
    Map<Integer, Integer> diag1 = new HashMap<>();
    Map<Integer, Integer> diag2 = new HashMap<>();
    Set<Long> lampsSet = new HashSet<>();

    for (int[] lamp : lamps) {
      final int i = lamp[0];
      final int j = lamp[1];
      if (lampsSet.add(hash(i, j))) {
        rows.merge(i, 1, Integer::sum);
        cols.merge(j, 1, Integer::sum);
        diag1.merge(i + j, 1, Integer::sum);
        diag2.merge(i - j, 1, Integer::sum);
      }
    }

    for (int[] query : queries) {
      final int i = query[0];
      final int j = query[1];
      if (rows.getOrDefault(i, 0) > 0 || cols.getOrDefault(j, 0) > 0 ||
          diag1.getOrDefault(i + j, 0) > 0 || diag2.getOrDefault(i - j, 0) > 0) {
        ans.add(1);
        for (int y = Math.max(0, i - 1); y < Math.min(n, i + 2); ++y)
          for (int x = Math.max(0, j - 1); x < Math.min(n, j + 2); ++x)
            if (lampsSet.remove(hash(y, x))) {
              rows.merge(y, 1, Integer::sum);
              cols.merge(x, 1, Integer::sum);
              diag1.merge(y + x, 1, Integer::sum);
              diag2.merge(y - x, 1, Integer::sum);
            }
      } else {
        ans.add(0);
      }
    }

    return ans.stream().mapToInt(Integer::intValue).toArray();
  }

  private long hash(int i, int j) {
    return ((long) i << 32) + j;
  }
}

class Solution {
 public:
  vector<int> gridIllumination(int n, vector<vector<int>>& lamps,
                               vector<vector<int>>& queries) {
    vector<int> ans;
    unordered_map<int, int> rows;
    unordered_map<int, int> cols;
    unordered_map<int, int> diag1;
    unordered_map<int, int> diag2;
    unordered_set<pair<int, int>, PairHash> lampsSet;

    for (const vector<int>& lamp : lamps) {
      const int i = lamp[0];
      const int j = lamp[1];
      if (lampsSet.insert({i, j}).second) {
        ++rows[i];
        ++cols[j];
        ++diag1[i + j];
        ++diag2[i - j];
      }
    }

    for (const vector<int>& query : queries) {
      const int i = query[0];
      const int j = query[1];
      if (rows[i] || cols[j] || diag1[i + j] || diag2[i - j]) {
        ans.push_back(1);
        for (int y = max(0, i - 1); y < min(n, i + 2); ++y)
          for (int x = max(0, j - 1); x < min(n, j + 2); ++x)
            if (lampsSet.erase({y, x})) {
              --rows[y];
              --cols[x];
              --diag1[y + x];
              --diag2[y - x];
            }
      } else {
        ans.push_back(0);
      }
    }

    return ans;
  }

 private:
  struct PairHash {
    size_t operator()(const pair<int, int>& p) const {
      return p.first ^ p.second;
    }
  };
};


You are given a large sample of integers in the range `[0, 255]`. Since the
sample is so large, it is represented by an array `count` where `count[k]` is
the number of times that `k` appears in the sample.

Calculate the following statistics:

* `minimum`: The minimum element in the sample.
* `maximum`: The maximum element in the sample.
* `mean`: The average of the sample, calculated as the total sum of all elements divided by the total number of elements.
* `median`:
* If the sample has an odd number of elements, then the `median` is the middle element once the sample is sorted.
* If the sample has an even number of elements, then the `median` is the average of the two middle elements once the sample is sorted.
* `mode`: The number that appears the most in the sample. It is guaranteed to be unique.

Return the statistics of the sample as an array of floating-point numbers
`[minimum, maximum, mean, median, mode]`. Answers within `10-5` of the actual
answer will be accepted.

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 sampleStats(self, count: List[int]) -> List[float]:
    minimum = next((i for i, num in enumerate(count) if num), None)
    maximum = next((i for i, num in reversed(list(enumerate(count))) if num), None)
    n = sum(count)
    mean = sum(i * c / n for i, c in enumerate(count))
    mode = count.index(max(count))

    numCount = 0
    leftMedian = 0
    for i, c in enumerate(count):
      numCount += c
      if numCount >= n / 2:
        leftMedian = i
        break

    numCount = 0
    rightMedian = 0
    for i, c in reversed(list(enumerate(count))):
      numCount += c
      if numCount >= n / 2:
        rightMedian = i
        break

    return [minimum, maximum, mean, (leftMedian + rightMedian) / 2, mode]

class Solution {
  public double[] sampleStats(int[] count) {
    final int n = Arrays.stream(count).sum();
    return new double[] {
        getMinimum(count),                                          //
        getMaximum(count),                                          //
        getMean(count, n),                                          //
        (getLeftMedian(count, n) + getRightMedian(count, n)) / 2.0, //
        getMode(count),
    };
  }

  private double getMinimum(int[] count) {
    for (int i = 0; i < count.length; ++i)
      if (count[i] > 0)
        return i;
    return -1;
  }

  private double getMaximum(int[] count) {
    for (int i = count.length - 1; i >= 0; --i)
      if (count[i] > 0)
        return i;
    return -1;
  }

  private double getMean(int[] count, double n) {
    double mean = 0;
    for (int i = 0; i < count.length; ++i)
      mean += ((long) i * (long) count[i]) / n;
    return mean;
  }

  private double getLeftMedian(int[] count, double n) {
    int numCount = 0;
    for (int i = 0; i < count.length; ++i) {
      numCount += count[i];
      if (numCount >= n / 2)
        return i;
    }
    return -1;
  }

  private double getRightMedian(int[] count, double n) {
    int numCount = 0;
    for (int i = count.length - 1; i >= 0; --i) {
      numCount += count[i];
      if (numCount >= n / 2)
        return i;
    }
    return -1;
  }

  private double getMode(int[] count) {
    int mode = -1;
    int maxCount = 0;
    for (int i = 0; i < count.length; ++i)
      if (count[i] > maxCount) {
        maxCount = count[i];
        mode = i;
      }
    return mode;
  }
}

class Solution {
 public:
  vector<double> sampleStats(vector<int>& count) {
    const int n = accumulate(count.begin(), count.end(), 0);
    const double mode = ranges::max_element(count) - count.begin();
    return {
        getMinimum(count),
        getMaximum(count),
        getMean(count, n),
        (getLeftMedian(count, n) + getRightMedian(count, n)) / 2.0,
        mode,
    };
  }

 private:
  double getMinimum(const vector<int>& count) {
    for (int i = 0; i < count.size(); ++i)
      if (count[i])
        return i;
    return -1;
  }

  double getMaximum(const vector<int>& count) {
    for (int i = count.size() - 1; i >= 0; --i)
      if (count[i])
        return i;
    return -1;
  }

  double getMean(const vector<int>& count, double n) {
    double mean = 0;
    for (long i = 0; i < count.size(); ++i)
      mean += (i * count[i]) / n;
    return mean;
  }

  double getLeftMedian(const vector<int>& count, double n) {
    int numCount = 0;
    for (int i = 0; i < count.size(); ++i) {
      numCount += count[i];
      if (numCount >= n / 2)
        return i;
    }
    return -1;
  }

  double getRightMedian(const vector<int>& count, double n) {
    int numCount = 0;
    for (int i = count.size() - 1; i >= 0; --i) {
      numCount += count[i];
      if (numCount >= n / 2)
        return i;
    }
    return -1;
  }
};


You are given an integer `n`, the number of nodes in a directed graph where
the nodes are labeled from `0` to `n - 1`. Each edge is red or blue in this
graph, and there could be self-edges and parallel edges.

You are given two arrays `redEdges` and `blueEdges` where:

* `redEdges[i] = [ai, bi]` indicates that there is a directed red edge from node `ai` to node `bi` in the graph, and
* `blueEdges[j] = [uj, vj]` indicates that there is a directed blue edge from node `uj` to node `vj` in the graph.

Return an array `answer` of length `n`, where each `answer[x]` is the length
of the shortest path from node `0` to node `x` such that the edge colors
alternate along the path, or `-1` if such a path does not exist.

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

from enum import Enum

class Color(Enum):
  kInit = 0
  kRed = 1
  kBlue = 2

class Solution:
  def shortestAlternatingPaths(self, n: int, redEdges: List[List[int]], blueEdges: List[List[int]]) -> List[int]:
    ans = [-1] * n
    graph = [[] for _ in range(n)]
    q = collections.deque([(0, Color.kInit)])

    for u, v in redEdges:
      graph[u].append((v, Color.kRed))

    for u, v in blueEdges:
      graph[u].append((v, Color.kBlue))

    step = 0
    while q:
      for _ in range(len(q)):
        u, prevColor = q.popleft()
        if ans[u] == -1:
          ans[u] = step
        for i, (v, edgeColor) in enumerate(graph[u]):
          if v == -1 or edgeColor == prevColor:
            continue
          q.append((v, edgeColor))
          graph[u][i] = (-1, edgeColor)
      step += 1

    return ans

enum Color { INIT, RED, BLUE }

class Solution {
  public int[] shortestAlternatingPaths(int n, int[][] redEdges, int[][] blueEdges) {
    int[] ans = new int[n];
    Arrays.fill(ans, -1);
    // graph[u] := [(v, edgeColor)]
    List<Pair<Integer, Color>>[] graph = new List[n];
    // [(u, prevColor)]
    Queue<Pair<Integer, Color>> q = new ArrayDeque<>(List.of(new Pair<>(0, Color.INIT)));
    Arrays.setAll(graph, i -> new ArrayList<>());

    for (int[] edge : redEdges) {
      final int u = edge[0];
      final int v = edge[1];
      graph[u].add(new Pair<>(v, Color.RED));
    }

    for (int[] edge : blueEdges) {
      final int u = edge[0];
      final int v = edge[1];
      graph[u].add(new Pair<>(v, Color.BLUE));
    }

    for (int step = 0; !q.isEmpty(); ++step)
      for (int sz = q.size(); sz > 0; --sz) {
        final int u = q.peek().getKey();
        Color prevColor = q.poll().getValue();
        ans[u] = ans[u] == -1 ? step : ans[u];
        for (int i = 0; i < graph[u].size(); ++i) {
          Pair<Integer, Color> node = graph[u].get(i);
          final int v = node.getKey();
          Color edgeColor = node.getValue();
          if (v == -1 || edgeColor == prevColor)
            continue;
          q.add(new Pair<>(v, edgeColor));
          // Mark (u, v) as used.
          graph[u].set(i, new Pair<>(-1, edgeColor));
        }
      }

    return ans;
  }
}

enum class Color { kInit, kRed, kBlue };

class Solution {
 public:
  vector<int> shortestAlternatingPaths(int n, vector<vector<int>>& redEdges,
                                       vector<vector<int>>& blueEdges) {
    vector<int> ans(n, -1);
    vector<vector<pair<int, Color>>> graph(n);  // graph[u] := [(v, edgeColor)]
    queue<pair<int, Color>> q{{{0, Color::kInit}}};  // [(u, prevColor)]

    for (const vector<int>& edge : redEdges) {
      const int u = edge[0];
      const int v = edge[1];
      graph[u].emplace_back(v, Color::kRed);
    }

    for (const vector<int>& edge : blueEdges) {
      const int u = edge[0];
      const int v = edge[1];
      graph[u].emplace_back(v, Color::kBlue);
    }

    for (int step = 0; !q.empty(); ++step)
      for (int sz = q.size(); sz > 0; --sz) {
        const auto [u, prevColor] = q.front();
        q.pop();
        ans[u] = ans[u] == -1 ? step : ans[u];
        for (auto& [v, edgeColor] : graph[u]) {
          if (v == -1 || edgeColor == prevColor)
            continue;
          q.emplace(v, edgeColor);
          v = -1;  // Mark (u, v) as used.
        }
      }

    return ans;
  }
};


Given a 2D `grid` of `0`s and `1`s, return the number of elements in the
largest square subgrid that has all `1`s on its border, or `0` if such a
subgrid doesn't exist in the `grid`.

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 largest1BorderedSquare(self, grid: List[List[int]]) -> int:
    m = len(grid)
    n = len(grid[0])

    leftOnes = [[0] * n for _ in range(m)]
    topOnes = [[0] * n for _ in range(m)]

    for i in range(m):
      for j in range(n):
        if grid[i][j] == 1:
          if j==0:
            leftOnes[i][j]=1
          else:
            leftOnes[i][j]=1+leftOnes[i][j-1]
          if i==0:
            topOnes[i][j]=1
          else:
            topOnes[i][j]=1+topOnes[i-1][j]

    for sz in range(min(m, n), 0, -1):
      for i in range(m - sz + 1):
        for j in range(n - sz + 1):
          x = i + sz - 1
          y = j + sz - 1
          if min(leftOnes[i][y], leftOnes[x][y], topOnes[x][j], topOnes[x][y]) >= sz:
            return sz * sz

    return 0

class Solution {
  public int largest1BorderedSquare(int[][] grid) {
    final int m = grid.length;
    final int n = grid[0].length;

    // leftOnes[i][j] := consecutive 1s in the left of grid[i][j]
    int[][] leftOnes = new int[m][n];
    // topOnes[i][j] := consecutive 1s in the top of grid[i][j]
    int[][] topOnes = new int[m][n];

    for (int i = 0; i < m; ++i)
      for (int j = 0; j < n; ++j)
        if (grid[i][j] == 1) {
          leftOnes[i][j] = j == 0 ? 1 : 1 + leftOnes[i][j - 1];
          topOnes[i][j] = i == 0 ? 1 : 1 + topOnes[i - 1][j];
        }

    for (int sz = Math.min(m, n); sz > 0; --sz)
      for (int i = 0; i + sz - 1 < m; ++i)
        for (int j = 0; j + sz - 1 < n; ++j) {
          final int x = i + sz - 1;
          final int y = j + sz - 1;
          // If grid[i..x][j..y] has all 1s on its border.
          if (Math.min(leftOnes[i][y], leftOnes[x][y]) >= sz &&
              Math.min(topOnes[x][j], topOnes[x][y]) >= sz)
            return sz * sz;
        }

    return 0;
  }
};

class Solution {
 public:
  int largest1BorderedSquare(vector<vector<int>>& grid) {
    const int m = grid.size();
    const int n = grid[0].size();

    // leftOnes[i][j] := consecutive 1s in the left of grid[i][j]
    vector<vector<int>> leftOnes(m, vector<int>(n));
    // topOnes[i][j] := consecutive 1s in the top of grid[i][j]
    vector<vector<int>> topOnes(m, vector<int>(n));

    for (int i = 0; i < m; ++i)
      for (int j = 0; j < n; ++j)
        if (grid[i][j] == 1) {
          leftOnes[i][j] = j == 0 ? 1 : 1 + leftOnes[i][j - 1];
          topOnes[i][j] = i == 0 ? 1 : 1 + topOnes[i - 1][j];
        }

    for (int sz = min(m, n); sz > 0; --sz)
      for (int i = 0; i + sz - 1 < m; ++i)
        for (int j = 0; j + sz - 1 < n; ++j) {
          const int x = i + sz - 1;
          const int y = j + sz - 1;
          // If grid[i..x][j..y] has all 1s on its border.
          if (min(leftOnes[i][y], leftOnes[x][y]) >= sz &&
              min(topOnes[x][j], topOnes[x][y]) >= sz)
            return sz * sz;
        }

    return 0;
  }
};


Given an `n x n` `grid` containing only values `0` and `1`, where `0`
represents water and `1` represents land, find a water cell such that its
distance to the nearest land cell is maximized, and return the distance. If no
land or water exists in the grid, return `-1`.

The distance used in this problem is the Manhattan distance: the distance
between two cells `(x0, y0)` and `(x1, y1)` is `|x0 - x1| + |y0 - y1|`.

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 maxDistance(self, grid: List[List[int]]) -> int:
    dirs = ((0, 1), (1, 0), (0, -1), (-1, 0))
    m = len(grid)
    n = len(grid[0])
    q = collections.deque()
    water = 0

    for i in range(m):
      for j in range(n):
        if grid[i][j] == 0:
          water += 1
        else:
          q.append((i, j))

    if water == 0 or water == m * n:
      return -1

    ans = 0
    d = 0

    while q:
      for _ in range(len(q)):
        i, j = q.popleft()
        ans = d
        for dx, dy in dirs:
          x = i + dx
          y = j + dy
          if x < 0 or x == m or y < 0 or y == n:
            continue
          if grid[x][y] > 0:
            continue
          q.append((x, y))
          grid[x][y] = 2
      d += 1

    return ans

class Solution {
  public int maxDistance(int[][] grid) {
    final int[][] DIRS = {{0, 1}, {1, 0}, {0, -1}, {-1, 0}};
    final int m = grid.length;
    final int n = grid[0].length;
    Queue<Pair<Integer, Integer>> q = new ArrayDeque<>();
    int water = 0;

    for (int i = 0; i < m; ++i)
      for (int j = 0; j < n; ++j)
        if (grid[i][j] == 0)
          ++water;
        else
          q.offer(new Pair<>(i, j));

    if (water == 0 || water == m * n)
      return -1;

    int ans = 0;

    for (int d = 0; !q.isEmpty(); ++d)
      for (int sz = q.size(); sz > 0; --sz) {
        Pair<Integer, Integer> pair = q.poll();
        final int i = pair.getKey();
        final int j = pair.getValue();
        ans = d;
        for (int[] dir : DIRS) {
          final int x = i + dir[0];
          final int y = j + dir[1];
          if (x < 0 || x == m || y < 0 || y == n)
            continue;
          if (grid[x][y] > 0)
            continue;
          q.offer(new Pair<>(x, y));
          grid[x][y] = 2; // Mark as visited.
        }
      }

    return ans;
  }
}

class Solution {
 public:
  int maxDistance(vector<vector<int>>& grid) {
    constexpr int kDirs[4][2] = {{0, 1}, {1, 0}, {0, -1}, {-1, 0}};
    const int m = grid.size();
    const int n = grid[0].size();
    queue<pair<int, int>> q;
    int water = 0;

    for (int i = 0; i < m; ++i)
      for (int j = 0; j < n; ++j)
        if (grid[i][j] == 0)
          ++water;
        else
          q.emplace(i, j);

    if (water == 0 || water == m * n)
      return -1;

    int ans = 0;

    for (int d = 0; !q.empty(); ++d)
      for (int sz = q.size(); sz > 0; --sz) {
        const auto [i, j] = q.front();
        q.pop();
        ans = d;
        for (const auto& [dx, dy] : kDirs) {
          const int x = i + dx;
          const int y = j + dy;
          if (x < 0 || x == m || y < 0 || y == n)
            continue;
          if (grid[x][y] > 0)
            continue;
          q.emplace(x, y);
          grid[x][y] = 2;  // Mark as visited.
        }
      }

    return ans;
  }
};


You are given a string `s`, and an array of pairs of indices in the string
`pairs` where `pairs[i] = [a, b]` indicates 2 indices(0-indexed) of the
string.

You can swap the characters at any pair of indices in the given `pairs` any
number of times.

Return the lexicographically smallest string that `s` can be changed to after
using the swaps.

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

class UnionFind:
  def __init__(self, n: int):
    self.id = list(range(n))
    self.rank = [0] * n

  def unionByRank(self, u: int, v: int) -> None:
    i = self.find(u)
    j = self.find(v)
    if i == j:
      return
    if self.rank[i] < self.rank[j]:
      self.id[i] = j
    elif self.rank[i] > self.rank[j]:
      self.id[j] = i
    else:
      self.id[i] = j
      self.rank[j] += 1

  def find(self, u: int) -> int:
    if self.id[u] != u:
      self.id[u] = self.find(self.id[u])
    return self.id[u]

class Solution:
  def smallestStringWithSwaps(self, s: str, pairs: List[List[int]]) -> str:
    ans = ''
    uf = UnionFind(len(s))
    map = collections.defaultdict(list)

    for a, b in pairs:
      uf.unionByRank(a, b)

    for i, c in enumerate(s):
      map[uf.find(i)].append(c)

    for key in map.keys():
      map[key].sort(reverse=True)

    for i in range(len(s)):
      ans += map[uf.find(i)].pop()

    return ans

class UnionFind {
  public UnionFind(int n) {
    id = new int[n];
    rank = new int[n];
    for (int i = 0; i < n; ++i)
      id[i] = i;
  }

  public void unionByRank(int u, int v) {
    final int i = find(u);
    final int j = find(v);
    if (i == j)
      return;
    if (rank[i] < rank[j]) {
      id[i] = j;
    } else if (rank[i] > rank[j]) {
      id[j] = i;
    } else {
      id[i] = j;
      ++rank[j];
    }
  }

  public int find(int u) {
    return id[u] == u ? u : (id[u] = find(id[u]));
  }

  private int[] id;
  private int[] rank;
}

class Solution {
  public String smallestStringWithSwaps(String s, List<List<Integer>> pairs) {
    StringBuilder sb = new StringBuilder();
    UnionFind uf = new UnionFind(s.length());
    Map<Integer, Queue<Character>> indexToLetters = new HashMap<>();

    for (List<Integer> pair : pairs) {
      final int a = pair.get(0);
      final int b = pair.get(1);
      uf.unionByRank(a, b);
    }

    for (int i = 0; i < s.length(); ++i)
      indexToLetters.computeIfAbsent(uf.find(i), k -> new PriorityQueue<>()).offer(s.charAt(i));

    for (int i = 0; i < s.length(); ++i)
      sb.append(indexToLetters.get(uf.find(i)).poll());

    return sb.toString();
  }
}

class UnionFind {
 public:
  UnionFind(int n) : id(n), rank(n) {
    iota(id.begin(), id.end(), 0);
  }

  void unionByRank(int u, int v) {
    const int i = find(u);
    const int j = find(v);
    if (i == j)
      return;
    if (rank[i] < rank[j]) {
      id[i] = j;
    } else if (rank[i] > rank[j]) {
      id[j] = i;
    } else {
      id[i] = j;
      ++rank[j];
    }
  }

  int find(int u) {
    return id[u] == u ? u : id[u] = find(id[u]);
  }

 private:
  vector<int> id;
  vector<int> rank;
};

class Solution {
 public:
  string smallestStringWithSwaps(string s, vector<vector<int>>& pairs) {
    string ans;
    UnionFind uf(s.length());
    unordered_map<int, priority_queue<char, vector<char>, greater<>>>
        indexToLetters;

    for (const vector<int>& pair : pairs) {
      const int a = pair[0];
      const int b = pair[1];
      uf.unionByRank(a, b);
    }

    for (int i = 0; i < s.length(); ++i)
      indexToLetters[uf.find(i)].push(s[i]);

    for (int i = 0; i < s.length(); ++i)
      ans += indexToLetters[uf.find(i)].top(), indexToLetters[uf.find(i)].pop();

    return ans;
  }
};


Minimum Moves to Reach Target with Rotations

In an `n*n` grid, there is a snake that spans 2 cells and starts moving from
the top left corner at `(0, 0)` and `(0, 1)`. The grid has empty cells
represented by zeros and blocked cells represented by ones. The snake wants to
reach the lower right corner at `(n-1, n-2)` and `(n-1, n-1)`.

In one move the snake can:

* Move one cell to the right if there are no blocked cells there. This move keeps the horizontal/vertical position of the snake as it is.
* Move down one cell if there are no blocked cells there. This move keeps the horizontal/vertical position of the snake as it is.
* Rotate clockwise if it's in a horizontal position and the two cells under it are both empty. In that case the snake moves from `(r, c)` and `(r, c+1)` to `(r, c)` and `(r+1, c)`.

* Rotate counterclockwise if it's in a vertical position and the two cells to its right are both empty. In that case the snake moves from `(r, c)` and `(r+1, c)` to `(r, c)` and `(r, c+1)`.

Return the minimum number of moves to reach the target.

If there is no way to reach the target, return `-1`.

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

from enum import IntEnum

class Pos(IntEnum):
  kHorizontal = 0
  kVertical = 1

class Solution:
  def minimumMoves(self, grid: List[List[int]]) -> int:
    n = len(grid)
    ans = 0

    q = collections.deque([(0, 0, Pos.kHorizontal)])
    seen = {(0, 0, Pos.kHorizontal)}

    def canMoveRight(x: int, y: int, pos: Pos) -> bool:
      if pos == Pos.kHorizontal:
        return y + 2 < n and not grid[x][y + 2]
      return y + 1 < n and not grid[x][y + 1] and not grid[x + 1][y + 1]

    def canMoveDown(x: int, y: int, pos: Pos) -> bool:
      if pos == Pos.kVertical:
        return x + 2 < n and not grid[x + 2][y]
      return x + 1 < n and not grid[x + 1][y] and not grid[x + 1][y + 1]

    def canRotateClockwise(x: int, y: int, pos: Pos) -> bool:
      return pos == Pos.kHorizontal and x + 1 < n and \
          not grid[x + 1][y + 1] and not grid[x + 1][y]

    def canRotateCounterclockwise(x: int, y: int, pos: Pos) -> bool:
      return pos == Pos.kVertical and y + 1 < n and \
          not grid[x + 1][y + 1] and not grid[x][y + 1]

    while q:
      for _ in range(len(q)):
        x, y, pos = q.popleft()
        if x == n - 1 and y == n - 2 and pos == Pos.kHorizontal:
          return ans
        if canMoveRight(x, y, pos) and (x, y + 1, pos) not in seen:
          q.append((x, y + 1, pos))
          seen.add((x, y + 1, pos))
        if canMoveDown(x, y, pos) and (x + 1, y, pos) not in seen:
          q.append((x + 1, y, pos))
          seen.add((x + 1, y, pos))
        newPos = Pos.kVertical if pos == Pos.kHorizontal else Pos.kHorizontal
        if (canRotateClockwise(x, y, pos) or canRotateCounterclockwise(x, y, pos)) and (x, y, newPos) not in seen:
          q.append((x, y, newPos))
          seen.add((x, y, newPos))
      ans += 1

    return -1

enum Pos { HORIZONTAL, VERTICAL }

class Solution {
  public int minimumMoves(int[][] grid) {
    record T(int x, int y, Pos pos) {}
    final int n = grid.length;
    Queue<T> q = new ArrayDeque<>(List.of(new T(0, 0, Pos.HORIZONTAL)));
    boolean[][][] seen = new boolean[n][n][2];
    seen[0][0][Pos.HORIZONTAL.ordinal()] = true;

    for (int step = 0; !q.isEmpty(); ++step)
      for (int sz = q.size(); sz > 0; --sz) {
        final int x = q.peek().x;
        final int y = q.peek().y;
        final Pos pos = q.poll().pos;
        if (x == n - 1 && y == n - 2 && pos == Pos.HORIZONTAL)
          return step;
        if (canMoveRight(grid, x, y, pos) && !seen[x][y + 1][pos.ordinal()]) {
          q.offer(new T(x, y + 1, pos));
          seen[x][y + 1][pos.ordinal()] = true;
        }
        if (canMoveDown(grid, x, y, pos) && !seen[x + 1][y][pos.ordinal()]) {
          q.offer(new T(x + 1, y, pos));
          seen[x + 1][y][pos.ordinal()] = true;
        }
        final Pos newPos = pos == Pos.HORIZONTAL ? Pos.VERTICAL : Pos.HORIZONTAL;
        if ((canRotateClockwise(grid, x, y, pos) || canRotateCounterclockwise(grid, x, y, pos)) &&
            !seen[x][y][newPos.ordinal()]) {
          q.offer(new T(x, y, newPos));
          seen[x][y][newPos.ordinal()] = true;
        }
      }

    return -1;
  }

  private boolean canMoveRight(int[][] grid, int x, int y, Pos pos) {
    if (pos == Pos.HORIZONTAL)
      return y + 2 < grid.length && grid[x][y + 2] == 0;
    return y + 1 < grid.length && grid[x][y + 1] == 0 && grid[x + 1][y + 1] == 0;
  }

  private boolean canMoveDown(int[][] grid, int x, int y, Pos pos) {
    if (pos == Pos.VERTICAL)
      return x + 2 < grid.length && grid[x + 2][y] == 0;
    return x + 1 < grid.length && grid[x + 1][y] == 0 && grid[x + 1][y + 1] == 0;
  }

  private boolean canRotateClockwise(int[][] grid, int x, int y, Pos pos) {
    return pos == Pos.HORIZONTAL && x + 1 < grid.length && grid[x + 1][y + 1] == 0 &&
        grid[x + 1][y] == 0;
  }

  private boolean canRotateCounterclockwise(int[][] grid, int x, int y, Pos pos) {
    return pos == Pos.VERTICAL && y + 1 < grid.length && grid[x + 1][y + 1] == 0 &&
        grid[x][y + 1] == 0;
  }
}

enum class Pos { kHorizontal, kVertical };

class Solution {
 public:
  int minimumMoves(vector<vector<int>>& grid) {
    const int n = grid.size();
    queue<tuple<int, int, Pos>> q{{{0, 0, Pos::kHorizontal}}};
    vector<vector<vector<bool>>> seen(n,
                                      vector<vector<bool>>(n, vector<bool>(2)));
    seen[0][0][static_cast<int>(Pos::kHorizontal)] = true;

    auto canMoveRight = [&](int x, int y, Pos pos) -> bool {
      if (pos == Pos::kHorizontal)
        return y + 2 < n && !grid[x][y + 2];
      return y + 1 < n && !grid[x][y + 1] && !grid[x + 1][y + 1];
    };

    auto canMoveDown = [&](int x, int y, Pos pos) -> bool {
      if (pos == Pos::kVertical)
        return x + 2 < n && !grid[x + 2][y];
      return x + 1 < n && !grid[x + 1][y] && !grid[x + 1][y + 1];
    };

    auto canRotateClockwise = [&](int x, int y, Pos pos) -> bool {
      return pos == Pos::kHorizontal && x + 1 < n && !grid[x + 1][y + 1] &&
             !grid[x + 1][y];
    };

    auto canRotateCounterclockwise = [&](int x, int y, Pos pos) -> bool {
      return pos == Pos::kVertical && y + 1 < n && !grid[x + 1][y + 1] &&
             !grid[x][y + 1];
    };

    for (int step = 0; !q.empty(); ++step)
      for (int sz = q.size(); sz > 0; --sz) {
        const auto [x, y, pos] = q.front();
        q.pop();
        if (x == n - 1 && y == n - 2 && pos == Pos::kHorizontal)
          return step;
        if (canMoveRight(x, y, pos) && !seen[x][y + 1][static_cast<int>(pos)]) {
          q.emplace(x, y + 1, pos);
          seen[x][y + 1][static_cast<int>(pos)] = true;
        }
        if (canMoveDown(x, y, pos) && !seen[x + 1][y][static_cast<int>(pos)]) {
          q.emplace(x + 1, y, pos);
          seen[x + 1][y][static_cast<int>(pos)] = true;
        }
        const Pos newPos =
            pos == Pos::kHorizontal ? Pos::kVertical : Pos::kHorizontal;
        if ((canRotateClockwise(x, y, pos) ||
             canRotateCounterclockwise(x, y, pos)) &&
            !seen[x][y][static_cast<int>(newPos)]) {
          q.emplace(x, y, newPos);
          seen[x][y][static_cast<int>(newPos)] = true;
        }
      }

    return -1;
  }
};


Given the following details of a matrix with `n` columns and `2` rows :

* The matrix is a binary matrix, which means each element in the matrix can be `0` or `1`.
* The sum of elements of the 0-th(upper) row is given as `upper`.
* The sum of elements of the 1-st(lower) row is given as `lower`.
* The sum of elements in the i-th column(0-indexed) is `colsum[i]`, where `colsum` is given as an integer array with length `n`.

Your task is to reconstruct the matrix with `upper`, `lower` and `colsum`.

Return it as a 2-D integer array.

If there are more than one valid solution, any of them will be accepted.

If no valid solution exists, return an empty 2-D array.

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 reconstructMatrix(self, upper: int, lower: int, colsum: List[int]) -> List[List[int]]:
    if upper + lower != sum(colsum):
      return []
    if min(upper, lower) < colsum.count(2):
      return []

    ans = [[0] * len(colsum) for _ in range(2)]

    for j, c in enumerate(colsum):
      if c == 2:
        ans[0][j] = 1
        ans[1][j] = 1
        upper -= 1
        lower -= 1

    for j, c in enumerate(colsum):
      if c == 1 and upper > 0:
        ans[0][j] = 1
        c -= 1
        upper -= 1
      if c == 1 and lower > 0:
        ans[1][j] = 1
        lower -= 1

    return ans

class Solution {
  public List<List<Integer>> reconstructMatrix(int upper, int lower, int[] colsum) {
    if (upper + lower != Arrays.stream(colsum).sum())
      return new ArrayList<>();

    int count = 0;
    for (int c : colsum)
      if (c == 2)
        ++count;

    if (Math.min(upper, lower) < count)
      return new ArrayList<>();

    int[][] ans = new int[2][colsum.length];

    for (int j = 0; j < colsum.length; ++j)
      if (colsum[j] == 2) {
        ans[0][j] = 1;
        ans[1][j] = 1;
        --upper;
        --lower;
      }

    for (int j = 0; j < colsum.length; ++j) {
      if (colsum[j] == 1 && upper > 0) {
        ans[0][j] = 1;
        --colsum[j];
        --upper;
      }

      if (colsum[j] == 1 && lower > 0) {
        ans[1][j] = 1;
        --lower;
      }
    }

    return new ArrayList(Arrays.asList(ans[0], ans[1]));
  }
}

class Solution {
 public:
  vector<vector<int>> reconstructMatrix(int upper, int lower,
                                        vector<int>& colsum) {
    if (upper + lower != accumulate(colsum.begin(), colsum.end(), 0))
      return {};
    if (min(upper, lower) <
        ranges::count_if(colsum, [](int c) { return c == 2; }))
      return {};

    vector<vector<int>> ans(2, vector<int>(colsum.size()));

    for (int j = 0; j < colsum.size(); ++j)
      if (colsum[j] == 2) {
        ans[0][j] = 1;
        ans[1][j] = 1;
        --upper;
        --lower;
      }

    for (int j = 0; j < colsum.size(); ++j) {
      if (colsum[j] == 1 && upper > 0) {
        ans[0][j] = 1;
        --colsum[j];
        --upper;
      }

      if (colsum[j] == 1 && lower > 0) {
        ans[1][j] = 1;
        --lower;
      }
    }

    return ans;
  }
};


Given a 2D `grid` consists of `0s` (land) and `1s` (water). An island is a
maximal 4-directionally connected group of `0s` and a closed island is an
island totally (all left, top, right, bottom) surrounded by `1s.`

Return the number of closed islands.

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 closedIsland(self, grid: List[List[int]]) -> int:
    m = len(grid)
    n = len(grid[0])

    def dfs(i: int, j: int) -> None:
      if i < 0 or i == m or j < 0 or j == n:
        return
      if grid[i][j] == 1:
        return

      grid[i][j] = 1
      dfs(i + 1, j)
      dfs(i - 1, j)
      dfs(i, j + 1)
      dfs(i, j - 1)

    for i in range(m):
      for j in range(n):
        if i * j == 0 or i == m - 1 or j == n - 1:
          if grid[i][j] == 0:
            dfs(i, j)

    ans = 0

    for i in range(m):
      for j in range(n):
        if grid[i][j] == 0:
          dfs(i, j)
          ans += 1

    return ans

class Solution {
  public int closedIsland(int[][] grid) {
    final int m = grid.length;
    final int n = grid[0].length;

    // Remove the lands connected to the edge.
    for (int i = 0; i < m; ++i)
      for (int j = 0; j < n; ++j)
        if (i * j == 0 || i == m - 1 || j == n - 1)
          if (grid[i][j] == 0)
            dfs(grid, i, j);

    int ans = 0;

    // Reduce to 200. Number of Islands
    for (int i = 0; i < m; ++i)
      for (int j = 0; j < n; ++j)
        if (grid[i][j] == 0) {
          dfs(grid, i, j);
          ++ans;
        }

    return ans;
  }

  private void dfs(int[][] grid, int i, int j) {
    if (i < 0 || i == grid.length || j < 0 || j == grid[0].length)
      return;
    if (grid[i][j] == 1)
      return;
    grid[i][j] = 1;
    dfs(grid, i + 1, j);
    dfs(grid, i - 1, j);
    dfs(grid, i, j + 1);
    dfs(grid, i, j - 1);
  }
}

class Solution {
 public:
  int closedIsland(vector<vector<int>>& grid) {
    const int m = grid.size();
    const int n = grid[0].size();

    // Remove the lands connected to the edge.
    for (int i = 0; i < m; ++i)
      for (int j = 0; j < n; ++j)
        if (i * j == 0 || i == m - 1 || j == n - 1)
          if (grid[i][j] == 0)
            dfs(grid, i, j);

    int ans = 0;

    // Reduce to 200. Number of Islands
    for (int i = 0; i < m; ++i)
      for (int j = 0; j < n; ++j)
        if (grid[i][j] == 0) {
          dfs(grid, i, j);
          ++ans;
        }

    return ans;
  }

 private:
  void dfs(vector<vector<int>>& grid, int i, int j) {
    if (i < 0 || i == grid.size() || j < 0 || j == grid[0].size())
      return;
    if (grid[i][j] == 1)
      return;
    grid[i][j] = 1;
    dfs(grid, i + 1, j);
    dfs(grid, i - 1, j);
    dfs(grid, i, j + 1);
    dfs(grid, i, j - 1);
  };
};


Minimum Moves to Move a Box to Their Target Location

A storekeeper is a game in which the player pushes boxes around in a warehouse
trying to get them to target locations.

The game is represented by an `m x n` grid of characters `grid` where each
element is a wall, floor, or box.

Your task is to move the box `'B'` to the target position `'T'` under the
following rules:

* The character `'S'` represents the player. The player can move up, down, left, right in `grid` if it is a floor (empty cell).
* The character `'.'` represents the floor which means a free cell to walk.
* The character `'#'` represents the wall which means an obstacle (impossible to walk there).
* There is only one box `'B'` and one target cell `'T'` in the `grid`.
* The box can be moved to an adjacent free cell by standing next to the box and then moving in the direction of the box. This is a push.
* The player cannot walk through the box.

Return the minimum number of pushes to move the box to the target. If there is
no way to reach the target, return `-1`.

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

class Solution:
  def minPushBox(self, grid: List[List[str]]) -> int:
    for i in range(len(grid)):
      for j in range(len(grid[0])):
        if grid[i][j] == "T":
          target = (i,j)
        if grid[i][j] == "B":
          box = (i,j)
        if grid[i][j] == "S":
          person = (i,j)

    def valid(x,y):
      return 0<=x<len(grid) and 0<=y<len(grid[0]) and grid[x][y]!='#'

    def check(curr,dest,box):
      que = deque([curr])
      v = set()
      while que:
        pos = que.popleft()
        if pos == dest:
          return True
        new_pos = [(pos[0]+1,pos[1]),(pos[0]-1,pos[1]),(pos[0],pos[1]+1),(pos[0],pos[1]-1)]
        for x,y in new_pos:
          if valid(x,y) and (x,y) not in v and (x,y)!=box:
            v.add((x,y))
            que.append((x,y))
      return False

    q = deque([(0,box,person)])
    vis = {box+person}
    while q :
      dist, box, person = q.popleft()
      if box == target:
        return dist

      b_coord = [(box[0]+1,box[1]),(box[0]-1,box[1]),(box[0],box[1]+1),(box[0],box[1]-1)]
      p_coord = [(box[0]-1,box[1]),(box[0]+1,box[1]),(box[0],box[1]-1),(box[0],box[1]+1)]

      for new_box,new_person in zip(b_coord,p_coord):
        if valid(*new_box) and new_box+box not in vis:
          if valid(*new_person) and check(person,new_person,box):
            vis.add(new_box+box)
            q.append((dist+1,new_box,box))

    return -1

class Solution {
  public int minPushBox(char[][] grid) {
    record T(int boxX, int boxY, int playerX, int playerY) {}
    final int m = grid.length;
    final int n = grid[0].length;
    int[] box = {-1, -1};
    int[] player = {-1, -1};
    int[] target = {-1, -1};

    for (int i = 0; i < m; ++i)
      for (int j = 0; j < n; ++j)
        if (grid[i][j] == 'B')
          box = new int[] {i, j};
        else if (grid[i][j] == 'S')
          player = new int[] {i, j};
        else if (grid[i][j] == 'T')
          target = new int[] {i, j};

    Queue<T> q = new ArrayDeque<>(List.of(new T(box[0], box[1], player[0], player[1])));
    boolean[][][][] seen = new boolean[m][n][m][n];
    seen[box[0]][box[1]][player[0]][player[1]] = true;

    for (int step = 0; !q.isEmpty(); ++step)
      for (int sz = q.size(); sz > 0; --sz) {
        final int boxX = q.peek().boxX;
        final int boxY = q.peek().boxY;
        final int playerX = q.peek().playerX;
        final int playerY = q.poll().playerY;
        if (boxX == target[0] && boxY == target[1])
          return step;
        for (int k = 0; k < 4; ++k) {
          final int nextBoxX = boxX + DIRS[k][0];
          final int nextBoxY = boxY + DIRS[k][1];
          if (isInvalid(grid, nextBoxX, nextBoxY))
            continue;
          if (seen[nextBoxX][nextBoxY][boxX][boxY])
            continue;
          final int fromX = boxX + DIRS[(k + 2) % 4][0];
          final int fromY = boxY + DIRS[(k + 2) % 4][1];
          if (isInvalid(grid, fromX, fromY))
            continue;
          if (canGoTo(grid, playerX, playerY, fromX, fromY, boxX, boxY)) {
            seen[nextBoxX][nextBoxY][boxX][boxY] = true;
            q.offer(new T(nextBoxX, nextBoxY, boxX, boxY));
          }
        }
      }

    return -1;
  }

  private static final int[][] DIRS = {{0, 1}, {1, 0}, {0, -1}, {-1, 0}};

  // Returns true if (playerX, playerY) can go to (fromX, fromY).
  private boolean canGoTo(char[][] grid, int playerX, int playerY, int fromX, int fromY, int boxX,
                          int boxY) {
    Queue<Pair<Integer, Integer>> q = new ArrayDeque<>(List.of(new Pair<>(playerX, playerY)));
    boolean[][] seen = new boolean[grid.length][grid[0].length];
    seen[playerX][playerY] = true;

    while (!q.isEmpty()) {
      final int i = q.peek().getKey();
      final int j = q.poll().getValue();
      if (i == fromX && j == fromY)
        return true;
      for (int[] dir : DIRS) {
        final int x = i + dir[0];
        final int y = j + dir[1];
        if (isInvalid(grid, x, y))
          continue;
        if (seen[x][y])
          continue;
        if (x == boxX && y == boxY)
          continue;
        q.offer(new Pair<>(x, y));
        seen[x][y] = true;
      }
    }

    return false;
  }

  private boolean isInvalid(char[][] grid, int playerX, int playerY) {
    return playerX < 0 || playerX == grid.length || playerY < 0 || playerY == grid[0].length ||
        grid[playerX][playerY] == '#';
  }
}

class Solution {
 public:
  int minPushBox(vector<vector<char>>& grid) {
    const int m = grid.size();
    const int n = grid[0].size();
    vector<int> box;
    vector<int> player;
    vector<int> target;

    for (int i = 0; i < m; ++i)
      for (int j = 0; j < n; ++j)
        if (grid[i][j] == 'B')
          box = {i, j};
        else if (grid[i][j] == 'S')
          player = {i, j};
        else if (grid[i][j] == 'T')
          target = {i, j};

    // (boxX, boxY, playerX, playerY)
    queue<tuple<int, int, int, int>> q{
        {{box[0], box[1], player[0], player[1]}}};
    vector<vector<vector<vector<bool>>>> seen(
        m, vector<vector<vector<bool>>>(
               n, vector<vector<bool>>(m, vector<bool>(n))));
    seen[box[0]][box[1]][player[0]][player[1]] = true;

    for (int step = 0; !q.empty(); ++step)
      for (int sz = q.size(); sz > 0; --sz) {
        const auto [boxX, boxY, playerX, playerY] = q.front();
        q.pop();
        if (boxX == target[0] && boxY == target[1])
          return step;
        for (int k = 0; k < 4; ++k) {
          const int nextBoxX = boxX + kDirs[k % 4][0];
          const int nextBoxY = boxY + kDirs[k % 4][1];
          if (isInvalid(grid, nextBoxX, nextBoxY))
            continue;
          if (seen[nextBoxX][nextBoxY][boxX][boxY])
            continue;
          const int fromX = boxX + kDirs[(k + 2) % 4][0];
          const int fromY = boxY + kDirs[(k + 2) % 4][1];
          if (isInvalid(grid, fromX, fromY))
            continue;
          if (canGoTo(grid, playerX, playerY, fromX, fromY, boxX, boxY)) {
            seen[nextBoxX][nextBoxY][boxX][boxY] = true;
            q.emplace(nextBoxX, nextBoxY, boxX, boxY);
          }
        }
      }

    return -1;
  }

 private:
  static constexpr int kDirs[4][2] = {{0, 1}, {1, 0}, {0, -1}, {-1, 0}};

  // Returns true if (playerX, playerY) can go to (fromX, fromY).
  bool canGoTo(const vector<vector<char>>& grid, int playerX, int playerY,
               int fromX, int fromY, int boxX, int boxY) {
    queue<pair<int, int>> q{{{playerX, playerY}}};
    vector<vector<bool>> seen(grid.size(), vector<bool>(grid[0].size()));
    seen[playerX][playerY] = true;

    while (!q.empty()) {
      const auto [i, j] = q.front();
      q.pop();
      if (i == fromX && j == fromY)
        return true;
      for (const auto& [dx, dy] : kDirs) {
        const int x = i + dx;
        const int y = j + dy;
        if (isInvalid(grid, x, y))
          continue;
        if (seen[x][y])
          continue;
        if (x == boxX && y == boxY)
          continue;
        q.emplace(x, y);
        seen[x][y] = true;
      }
    }

    return false;
  }

  bool isInvalid(const vector<vector<char>>& grid, int playerX, int playerY) {
    return playerX < 0 || playerX == grid.size() || playerY < 0 ||
           playerY == grid[0].size() || grid[playerX][playerY] == '#';
  }
};