You are given an `m x n` matrix `maze` (0-indexed) with empty cells
(represented as `'.'`) and walls (represented as `'+'`). You are also given
the `entrance` of the maze, where `entrance = [entrancerow, entrancecol]`
denotes the row and column of the cell you are initially standing at.

In one step, you can move one cell up, down, left, or right. You cannot step
into a cell with a wall, and you cannot step outside the maze. Your goal is to
find the nearest exit from the `entrance`. An exit is defined as an empty cell
that is at the border of the `maze`. The `entrance` does not count as an exit.

Return the number of steps in the shortest path from the `entrance` to the
nearest exit, or `-1` if no such path exists.

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 nearestExit(self, maze: List[List[str]], entrance: List[int]) -> int:
    dirs = ((0, 1), (1, 0), (0, -1), (-1, 0))
    m = len(maze)
    n = len(maze[0])
    ans = 0
    q = collections.deque([(entrance[0], entrance[1])])
    seen = {(entrance[0], entrance[1])}

    while q:
      ans += 1
      for _ in range(len(q)):
        i, j = q.popleft()
        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 (x, y) in seen or maze[x][y] == '+':
            continue
          if x == 0 or x == m - 1 or y == 0 or y == n - 1:
            return ans
          q.append((x, y))
          seen.add((x, y))

    return -1

class Solution {
  public int nearestExit(char[][] maze, int[] entrance) {
    final int[][] DIRS = {{0, 1}, {1, 0}, {0, -1}, {-1, 0}};
    final int m = maze.length;
    final int n = maze[0].length;
    Queue<Pair<Integer, Integer>> q =
        new ArrayDeque<>(List.of(new Pair<>(entrance[0], entrance[1])));
    boolean[][] seen = new boolean[m][n];
    seen[entrance[0]][entrance[1]] = true;

    for (int step = 1; !q.isEmpty(); ++step)
      for (int sz = q.size(); sz > 0; --sz) {
        final int i = q.peek().getKey();
        final int j = q.poll().getValue();
        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 (seen[x][y] || maze[x][y] == '+')
            continue;
          if (x == 0 || x == m - 1 || y == 0 || y == n - 1)
            return step;
          q.offer(new Pair<>(x, y));
          seen[x][y] = true;
        }
      }

    return -1;
  }
}

class Solution {
 public:
  int nearestExit(vector<vector<char>>& maze, vector<int>& entrance) {
    constexpr int kDirs[4][2] = {{0, 1}, {1, 0}, {0, -1}, {-1, 0}};
    const int m = maze.size();
    const int n = maze[0].size();
    queue<pair<int, int>> q{{{entrance[0], entrance[1]}}};
    vector<vector<bool>> seen(m, vector<bool>(n));
    seen[entrance[0]][entrance[1]] = true;

    for (int step = 1; !q.empty(); ++step)
      for (int sz = q.size(); sz > 0; --sz) {
        const auto [i, j] = q.front();
        q.pop();
        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 (seen[x][y] || maze[x][y] == '+')
            continue;
          if (x == 0 || x == m - 1 || y == 0 || y == n - 1)
            return step;
          q.emplace(x, y);
          seen[x][y] = true;
        }
      }

    return -1;
  }
};


Minimum Cost to Reach Destination in Time

There is a country of `n` cities numbered from `0` to `n - 1` where all the
cities are connected by bi-directional roads. The roads are represented as a
2D integer array `edges` where `edges[i] = [xi, yi, timei]` denotes a road
between cities `xi` and `yi` that takes `timei` minutes to travel. There may
be multiple roads of differing travel times connecting the same two cities,
but no road connects a city to itself.

Each time you pass through a city, you must pay a passing fee. This is
represented as a 0-indexed integer array `passingFees` of length `n` where
`passingFees[j]` is the amount of dollars you must pay when you pass through
city `j`.

In the beginning, you are at city `0` and want to reach city `n - 1` in
`maxTime` minutes or less. The cost of your journey is the summation of
passing fees for each city that you passed through at some moment of your
journey (including the source and destination cities).

Given `maxTime`, `edges`, and `passingFees`, return the minimum cost to
complete your journey, or `-1` if you cannot complete it within `maxTime`
minutes.

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 minCost(self, maxTime: int, edges: List[List[int]], passingFees: List[int]) -> int:
    n = len(passingFees)
    graph = [[] for _ in range(n)]

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

    return self._dijkstra(graph, 0, n - 1, maxTime, passingFees)

  def _dijkstra(self, graph: List[List[Tuple[int, int]]], src: int, dst: int, maxTime: int, passingFees: List[int]) -> int:
    cost = [math.inf for _ in range(len(graph))]
    dist = [maxTime + 1 for _ in range(len(graph))]

    cost[src] = passingFees[src]
    dist[src] = 0
    minHeap = [(cost[src], dist[src], src)]

    while minHeap:
      currCost, d, u = heapq.heappop(minHeap)
      if u == dst:
        return cost[dst]
      if d > dist[u] and currCost > cost[u]:
        continue
      for v, w in graph[u]:
        if d + w > maxTime:
          continue
        if currCost + passingFees[v] < cost[v]:
          cost[v] = currCost + passingFees[v]
          dist[v] = d + w
          heapq.heappush(minHeap, (cost[v], dist[v], v))
        elif d + w < dist[v]:
          dist[v] = d + w
          heapq.heappush(minHeap, (currCost + passingFees[v], dist[v], v))

    return -1

class Solution {
  public int minCost(int maxTime, int[][] edges, int[] passingFees) {
    final int n = passingFees.length;
    List<Pair<Integer, Integer>>[] graph = new List[n];
    Arrays.setAll(graph, i -> new ArrayList<>());

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

    return dijkstra(graph, 0, n - 1, maxTime, passingFees);
  }

  private int dijkstra(List<Pair<Integer, Integer>>[] graph, int src, int dst, int maxTime,
                       int[] passingFees) {
    int[] cost = new int[graph.length]; // cost[i] := the minimum cost to reach the i-th city
    int[] dist = new int[graph.length]; // dist[i] := the minimum distance to reach the i-th city
    Arrays.fill(cost, Integer.MAX_VALUE);
    Arrays.fill(dist, maxTime + 1);

    cost[0] = passingFees[0];
    dist[0] = 0;
    Queue<int[]> minHeap = new PriorityQueue<>(Comparator.comparingInt(a -> a[0])) {
      { offer(new int[] {cost[src], dist[src], src}); } // (cost[u], dist[u], u)
    };

    while (!minHeap.isEmpty()) {
      final int currCost = minHeap.peek()[0];
      final int d = minHeap.peek()[1];
      final int u = minHeap.poll()[2];
      if (u == dst)
        return cost[dst];
      if (d > dist[u] && currCost > cost[u])
        continue;
      for (Pair<Integer, Integer> pair : graph[u]) {
        final int v = pair.getKey();
        final int w = pair.getValue();
        if (d + w > maxTime)
          continue;
        // Go from x -> y
        if (currCost + passingFees[v] < cost[v]) {
          cost[v] = currCost + passingFees[v];
          dist[v] = d + w;
          minHeap.offer(new int[] {cost[v], dist[v], v});
        } else if (d + w < dist[v]) {
          dist[v] = d + w;
          minHeap.offer(new int[] {currCost + passingFees[v], dist[v], v});
        }
      }
    }

    return -1;
  }
}

class Solution {
 public:
  int minCost(int maxTime, vector<vector<int>>& edges,
              vector<int>& passingFees) {
    const int n = passingFees.size();
    vector<vector<pair<int, int>>> graph(n);

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

    return dijkstra(graph, 0, n - 1, maxTime, passingFees);
  }

 private:
  int dijkstra(const vector<vector<pair<int, int>>>& graph, int src, int dst,
               int maxTime, const vector<int>& passingFees) {
    // cost[i] := the minimum cost to reach the i-th city
    vector<int> cost(graph.size(), INT_MAX);
    // dist[i] := the minimum time to reach the i-th city
    vector<int> dist(graph.size(), maxTime + 1);

    cost[src] = passingFees[src];
    dist[src] = 0;
    using T = tuple<int, int, int>;  // (cost[u], dist[u], u)
    priority_queue<T, vector<T>, greater<>> minHeap;
    minHeap.emplace(cost[src], dist[src], src);

    while (!minHeap.empty()) {
      const auto [currCost, d, u] = minHeap.top();
      minHeap.pop();
      if (u == dst)
        return cost[dst];
      if (d > dist[u] && currCost > cost[u])
        continue;
      for (const auto& [v, w] : graph[u]) {
        if (d + w > maxTime)
          continue;
        // Go from u -> v.
        if (currCost + passingFees[v] < cost[v]) {
          cost[v] = currCost + passingFees[v];
          dist[v] = d + w;
          minHeap.emplace(cost[v], dist[v], v);
        } else if (d + w < dist[v]) {
          dist[v] = d + w;
          minHeap.emplace(currCost + passingFees[v], dist[v], v);
        }
      }
    }

    return -1;
  }
};


There is a rooted tree consisting of `n` nodes numbered `0` to `n - 1`. Each
node's number denotes its unique genetic value (i.e. the genetic value of node
`x` is `x`). The genetic difference between two genetic values is defined as
the bitwise-XOR of their values. You are given the integer array `parents`,
where `parents[i]` is the parent for node `i`. If node `x` is the root of the
tree, then `parents[x] == -1`.

You are also given the array `queries` where `queries[i] = [nodei, vali]`. For
each query `i`, find the maximum genetic difference between `vali` and `pi`,
where `pi` is the genetic value of any node that is on the path between
`nodei` and the root (including `nodei` and the root). More formally, you want
to maximize `vali XOR pi`.

Return an array `ans` where `ans[i]` is the answer to the `ith` query.

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

class TrieNode:
  def __init__(self):
    self.children = [None] * 2
    self.count = 0

class Trie:
  def __init__(self):
    self.root = TrieNode()
    self.kHeight = 17

  def update(self, num: int, val: int) -> None:
    node = self.root
    for i in range(self.kHeight, -1, -1):
      bit = (num >> i) & 1
      if not node.children[bit]:
        node.children[bit] = TrieNode()
      node = node.children[bit]
      node.count += val

  def query(self, num: int) -> int:
    ans = 0
    node = self.root
    for i in range(self.kHeight, -1, -1):
      bit = (num >> i) & 1
      targetBit = bit ^ 1
      if node.children[targetBit] and node.children[targetBit].count > 0:
        ans += 1 << i
        node = node.children[targetBit]
      else:
        node = node.children[targetBit ^ 1]
    return ans

class Solution:
  def maxGeneticDifference(self, parents: List[int], queries: List[List[int]]) -> List[int]:
    n = len(parents)
    ans = [0] * len(queries)
    rootVal = -1
    tree = [[] for _ in range(n)]
    nodeToQueries = collections.defaultdict(list)
    trie = Trie()

    for i, parent in enumerate(parents):
      if parent == -1:
        rootVal = i
      else:
        tree[parent].append(i)

    for i, (node, val) in enumerate(queries):
      nodeToQueries[node].append((i, val))

    def dfs(node: int) -> None:
      trie.update(node, 1)

      for i, val in nodeToQueries[node]:
        ans[i] = trie.query(val)

      for child in tree[node]:
        dfs(child)

      trie.update(node, -1)

    dfs(rootVal)
    return ans

class TrieNode {
  public TrieNode[] children = new TrieNode[2];
  public int count = 0;
}

class Trie {
  public void update(int num, int val) {
    TrieNode node = root;
    for (int i = HEIGHT; i >= 0; --i) {
      final int bit = (num >> i) & 1;
      if (node.children[bit] == null)
        node.children[bit] = new TrieNode();
      node = node.children[bit];
      node.count += val;
    }
  }

  public int query(int num) {
    int ans = 0;
    TrieNode node = root;
    for (int i = HEIGHT; i >= 0; --i) {
      final int bit = (num >> i) & 1;
      final int targetBit = bit ^ 1;
      if (node.children[targetBit] != null && node.children[targetBit].count > 0) {
        ans += 1 << i;
        node = node.children[targetBit];
      } else {
        node = node.children[targetBit ^ 1];
      }
    }
    return ans;
  }

  private static final int HEIGHT = 17;
  TrieNode root = new TrieNode();
}

class Solution {
  public int[] maxGeneticDifference(int[] parents, int[][] queries) {
    final int n = parents.length;
    int[] ans = new int[queries.length];
    int rootVal = -1;
    List<Integer>[] tree = new List[n];

    for (int i = 0; i < n; ++i)
      tree[i] = new ArrayList<>();

    // {node: (index, val)}
    Map<Integer, List<Pair<Integer, Integer>>> nodeToQueries = new HashMap<>();
    Trie trie = new Trie();

    for (int i = 0; i < parents.length; ++i)
      if (parents[i] == -1)
        rootVal = i;
      else
        tree[parents[i]].add(i);

    for (int i = 0; i < queries.length; ++i) {
      final int node = queries[i][0];
      final int val = queries[i][1];
      nodeToQueries.putIfAbsent(node, new ArrayList<>());
      nodeToQueries.get(node).add(new Pair<>(i, val));
    }

    dfs(rootVal, trie, tree, nodeToQueries, ans);
    return ans;
  }

  private void dfs(int node, Trie trie, List<Integer>[] tree,
                   Map<Integer, List<Pair<Integer, Integer>>> nodeToQueries, int[] ans) {
    trie.update(node, 1);

    if (nodeToQueries.containsKey(node))
      for (Pair<Integer, Integer> query : nodeToQueries.get(node)) {
        final int i = query.getKey();
        final int val = query.getValue();
        ans[i] = trie.query(val);
      }

    for (final int child : tree[node])
      dfs(child, trie, tree, nodeToQueries, ans);

    trie.update(node, -1);
  }
}

struct TrieNode {
  vector<shared_ptr<TrieNode>> children;
  int count = 0;
  TrieNode() : children(2) {}
};

class Trie {
 public:
  void update(int num, int val) {
    shared_ptr<TrieNode> node = root;
    for (int i = kHeight; i >= 0; --i) {
      const int bit = (num >> i) & 1;
      if (node->children[bit] == nullptr)
        node->children[bit] = make_shared<TrieNode>();
      node = node->children[bit];
      node->count += val;
    }
  }

  int query(int num) {
    int ans = 0;
    shared_ptr<TrieNode> node = root;
    for (int i = kHeight; i >= 0; --i) {
      const int bit = (num >> i) & 1;
      const int targetBit = bit ^ 1;
      if (node->children[targetBit] && node->children[targetBit]->count) {
        ans += 1 << i;
        node = node->children[targetBit];
      } else {
        node = node->children[targetBit ^ 1];
      }
    }
    return ans;
  }

 private:
  static constexpr int kHeight = 17;
  shared_ptr<TrieNode> root = make_shared<TrieNode>();
};

class Solution {
 public:
  vector<int> maxGeneticDifference(vector<int>& parents,
                                   vector<vector<int>>& queries) {
    const int n = parents.size();
    vector<int> ans(queries.size());
    int rootVal = -1;
    vector<vector<int>> tree(n);
    // {node: (index, val)}
    unordered_map<int, vector<pair<int, int>>> nodeToQueries;
    Trie trie;

    for (int i = 0; i < parents.size(); ++i)
      if (parents[i] == -1)
        rootVal = i;
      else
        tree[parents[i]].push_back(i);

    for (int i = 0; i < queries.size(); ++i) {
      const int node = queries[i][0];
      const int val = queries[i][1];
      nodeToQueries[node].emplace_back(i, val);
    }

    dfs(rootVal, trie, tree, nodeToQueries, ans);
    return ans;
  }

 private:
  void dfs(int node, Trie& trie, const vector<vector<int>>& tree,
           const unordered_map<int, vector<pair<int, int>>>& nodeToQueries,
           vector<int>& ans) {
    trie.update(node, 1);

    if (const auto it = nodeToQueries.find(node); it != nodeToQueries.cend())
      for (const auto& [i, val] : it->second)
        ans[i] = trie.query(val);

    for (const int child : tree[node])
      dfs(child, trie, tree, nodeToQueries, ans);

    trie.update(node, -1);
  }
};


There is a bi-directional graph with `n` vertices, where each vertex is
labeled from `0` to `n - 1` (inclusive). The edges in the graph are
represented as a 2D integer array `edges`, where each `edges[i] = [ui, vi]`
denotes a bi-directional edge between vertex `ui` and vertex `vi`. Every
vertex pair is connected by at most one edge, and no vertex has an edge to
itself.

You want to determine if there is a valid path that exists from vertex
`source` to vertex `destination`.

Given `edges` and the integers `n`, `source`, and `destination`, return `true`
if there is a valid path from `source` to `destination`, 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))
    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 validPath(self, n: int, edges: List[List[int]], source: int, destination: int) -> bool:
    uf = UnionFind(n)

    for u, v in edges:
      uf.unionByRank(u, v)

    return uf.find(source) == uf.find(destination)

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 validPath(int n, int[][] edges, int source, int destination) {
    UnionFind uf = new UnionFind(n);

    for (int[] edge : edges) {
      final int u = edge[0];
      final int v = edge[1];
      uf.unionByRank(u, v);
    }

    return uf.find(source) == uf.find(destination);
  }
}

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:
  bool validPath(int n, vector<vector<int>>& edges, int source,
                 int destination) {
    UnionFind uf(n);

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

    return uf.find(source) == uf.find(destination);
  }
};


You are in a city that consists of `n` intersections numbered from `0` to `n -
1` with bi-directional roads between some intersections. The inputs are
generated such that you can reach any intersection from any other intersection
and that there is at most one road between any two intersections.

You are given an integer `n` and a 2D integer array `roads` where `roads[i] =
[ui, vi, timei]` means that there is a road between intersections `ui` and
`vi` that takes `timei` minutes to travel. You want to know in how many ways
you can travel from intersection `0` to intersection `n - 1` in the shortest
amount of time.

Return the number of ways you can arrive at your destination in the shortest
amount of time. Since the answer may be 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 countPaths(self, n: int, roads: List[List[int]]) -> int:
    graph = [[] for _ in range(n)]

    for u, v, w in roads:
      graph[u].append((v, w))
      graph[v].append((u, w))

    return self._dijkstra(graph, 0, n - 1)

  def _dijkstra(self, graph: List[List[Tuple[int, int]]], src: int, dst: int) -> int:
    kMod = 10**9 + 7
    ways = [0] * len(graph)
    dist = [math.inf] * len(graph)

    ways[src] = 1
    dist[src] = 0
    minHeap = [(dist[src], src)]

    while minHeap:
      d, u = heapq.heappop(minHeap)
      if d > dist[u]:
        continue
      for v, w in graph[u]:
        if d + w < dist[v]:
          dist[v] = d + w
          ways[v] = ways[u]
          heapq.heappush(minHeap, (dist[v], v))
        elif d + w == dist[v]:
          ways[v] += ways[u]
          ways[v] %= kMod

    return ways[dst]

class Solution {
  public int countPaths(int n, int[][] roads) {
    List<Pair<Integer, Integer>>[] graph = new List[n];

    for (int i = 0; i < n; i++)
      graph[i] = new ArrayList<>();

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

    return dijkstra(graph, 0, n - 1);
  }

  private int dijkstra(List<Pair<Integer, Integer>>[] graph, int src, int dst) {
    final int MOD = 1_000_000_007;
    long[] ways = new long[graph.length];
    Arrays.fill(ways, 0);
    long[] dist = new long[graph.length];
    Arrays.fill(dist, Long.MAX_VALUE);

    ways[src] = 1;
    dist[src] = 0;
    Queue<Pair<Long, Integer>> minHeap =
        new PriorityQueue<>(Comparator.comparingLong(Pair::getKey)) {
          { offer(new Pair<>(dist[src], src)); }
        };

    while (!minHeap.isEmpty()) {
      final long d = minHeap.peek().getKey();
      final int u = minHeap.poll().getValue();
      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 < dist[v]) {
          dist[v] = d + w;
          ways[v] = ways[u];
          minHeap.offer(new Pair<>(dist[v], v));
        } else if (d + w == dist[v]) {
          ways[v] += ways[u];
          ways[v] %= MOD;
        }
      }
    }

    return (int) ways[dst];
  }
}

class Solution {
 public:
  int countPaths(int n, vector<vector<int>>& roads) {
    vector<vector<pair<int, int>>> graph(n);

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

    return dijkstra(graph, 0, n - 1);
  }

 private:
  // Similar to 1786. Number of Restricted Paths From First to Last Node
  int dijkstra(const vector<vector<pair<int, int>>>& graph, int src, int dst) {
    constexpr int kMod = 1'000'000'007;
    vector<long> ways(graph.size());
    vector<long> dist(graph.size(), LONG_MAX);

    ways[src] = 1;
    dist[src] = 0;
    using P = pair<long, 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();
      if (d > dist[u])
        continue;
      for (const auto& [v, w] : graph[u])
        if (d + w < dist[v]) {
          dist[v] = d + w;
          ways[v] = ways[u];
          minHeap.emplace(dist[v], v);
        } else if (d + w == dist[v]) {
          ways[v] += ways[u];
          ways[v] %= kMod;
        }
    }

    return ways[dst];
  }
};


You wrote down many positive integers in a string called `num`. However, you
realized that you forgot to add commas to seperate the different numbers. You
remember that the list of integers was non-decreasing and that no integer had
leading zeros.

Return the number of possible lists of integers that you could have written
down to get the string `num`. Since the answer may be 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 numberOfCombinations(self, num: str) -> int:
    if num[0] == '0':
      return 0

    kMod = 1_000_000_007
    n = len(num)
    dp = [[0] * (n + 1) for _ in range(n)]
    lcs = [[0] * (n + 1) for _ in range(n + 1)]

    for i in range(n - 1, -1, -1):
      for j in range(i + 1, n):
        if num[i] == num[j]:
          lcs[i][j] = lcs[i + 1][j + 1] + 1

    for i in range(n):
      for k in range(1, i + 2):
        dp[i][k] += dp[i][k - 1]
        dp[i][k] %= kMod
        s = i - k + 1
        if num[s] == '0':
          continue
        if s == 0:
          dp[i][k] += 1
          continue
        if s < k:
          dp[i][k] += dp[s - 1][s]
          continue
        l = lcs[s - k][s]
        if l >= k or num[s - k + l] <= num[s + l]:
          dp[i][k] += dp[s - 1][k]
        else:
          dp[i][k] += dp[s - 1][k - 1]

    return dp[n - 1][n] % kMod

class Solution {
  public int numberOfCombinations(String num) {
    if (num.charAt(0) == '0')
      return 0;

    final int MOD = 1_000_000_007;
    final int n = num.length();
    // dp[i][k] := the number of possible lists of integers ending in num[i] with
    // the length of the last number being 1..k
    long[][] dp = new long[n][n + 1];
    // lcs[i][j] := the number of the same digits in num[i..n) and num[j..n)
    int[][] lcs = new int[n + 1][n + 1];

    for (int i = n - 1; i >= 0; --i)
      for (int j = i + 1; j < n; ++j)
        if (num.charAt(i) == num.charAt(j))
          lcs[i][j] = lcs[i + 1][j + 1] + 1;

    for (int i = 0; i < n; ++i)
      for (int k = 1; k <= i + 1; ++k) {
        dp[i][k] += dp[i][k - 1];
        dp[i][k] %= MOD;
        // The last number is num[s..i].
        final int s = i - k + 1;
        if (num.charAt(s) == '0')
          // the number of possible lists of integers ending in num[i] with the
          // length of the last number being k
          continue;
        if (s == 0) {
          // the whole string
          dp[i][k] += 1;
          continue;
        }
        if (s < k) {
          // The length k is not enough, so add the number of possible lists of
          // integers in num[0..s - 1].
          dp[i][k] += dp[s - 1][s];
          continue;
        }
        final int l = lcs[s - k][s];
        if (l >= k || num.charAt(s - k + l) <= num.charAt(s + l))
          // Have enough length k and num[s - k..s - 1] <= num[j..i].
          dp[i][k] += dp[s - 1][k];
        else
          // Have enough length k but num[s - k..s - 1] > num[j..i].
          dp[i][k] += dp[s - 1][k - 1];
      }

    return (int) dp[n - 1][n] % MOD;
  }
}

class Solution {
 public:
  int numberOfCombinations(string num) {
    if (num[0] == '0')
      return 0;

    constexpr int kMod = 1'000'000'007;
    const int n = num.size();
    // dp[i][k] := the number of possible lists of integers ending in num[i]
    // with the length of the last number being 1..k
    vector<vector<long>> dp(n, vector<long>(n + 1));
    // lcs[i][j] := the number of the same digits in num[i..n) and num[j..n)
    vector<vector<int>> lcs(n + 1, vector<int>(n + 1));

    for (int i = n - 1; i >= 0; --i)
      for (int j = i + 1; j < n; ++j)
        if (num[i] == num[j])
          lcs[i][j] = lcs[i + 1][j + 1] + 1;

    for (int i = 0; i < n; ++i)
      for (int k = 1; k <= i + 1; ++k) {
        dp[i][k] += dp[i][k - 1];
        dp[i][k] %= kMod;
        // The last number is num[s..i].
        const int s = i - k + 1;
        if (num[s] == '0')
          // the number of possible lists of integers ending in num[i] with the
          // length of the last number being k
          continue;
        if (s == 0) {
          // the whole string
          dp[i][k] += 1;
          continue;
        }
        if (s < k) {
          // The length k is not enough, so add the number of possible lists of
          // integers in num[0..s - 1].
          dp[i][k] += dp[s - 1][s];
          continue;
        }
        const int l = lcs[s - k][s];
        if (l >= k || num[s - k + l] <= num[s + l])
          // Have enough length k and num[s - k..s - 1] <= num[j..i].
          dp[i][k] += dp[s - 1][k];
        else
          // Have enough length k but num[s - k..s - 1] > num[j..i].
          dp[i][k] += dp[s - 1][k - 1];
      }

    return dp[n - 1][n] % kMod;
  }
};


You are given an integer array `nums`. We call a subset of `nums` good if its
product can be represented as a product of one or more distinct prime numbers.

* For example, if `nums = [1, 2, 3, 4]`:
* `[2, 3]`, `[1, 2, 3]`, and `[1, 3]` are good subsets with products `6 = 2*3`, `6 = 2*3`, and `3 = 3` respectively.
* `[1, 4]` and `[4]` are not good subsets with products `4 = 2*2` and `4 = 2*2` respectively.

Return the number of different good subsets in `nums` modulo `109 + 7`.

A subset of `nums` is any array that can be obtained by deleting some
(possibly none or all) elements from `nums`. Two subsets are different if and
only if the chosen indices to delete are different.

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 numberOfGoodSubsets(self, nums: List[int]) -> int:
    kMod = 1_000_000_007
    primes = [2, 3, 5, 7, 11, 13, 17, 19, 23, 29]
    n = 1 << len(primes)
    dp = [1] + [0] * (n - 1)
    count = collections.Counter(nums)

    for num, freq in count.items():
      if num == 1:
        continue
      if any(num % squared == 0 for squared in [4, 9, 25]):
        continue
      numPrimesMask = 0
      for i, prime in enumerate(primes):
        if num % prime == 0:
          numPrimesMask += 1 << i
      for primesMask in range(n):
        if primesMask & numPrimesMask > 0:
          continue
        nextPrimesMask = numPrimesMask | primesMask
        dp[nextPrimesMask] += dp[primesMask] * freq
        dp[nextPrimesMask] %= kMod

    return (1 << count[1]) * sum(dp[1:]) % kMod

class Solution {
  public int numberOfGoodSubsets(int[] nums) {
    final int[] primes = {2, 3, 5, 7, 11, 13, 17, 19, 23, 29};
    final int n = 1 << primes.length;
    final int maxNum = Arrays.stream(nums).max().getAsInt();
    long[] dp = new long[n];
    int[] count = new int[maxNum + 1];

    dp[0] = 1;

    for (final int num : nums)
      ++count[num];

    for (int num = 2; num <= maxNum; ++num) {
      if (count[num] == 0)
        continue;
      if (num % 4 == 0 || num % 9 == 0 || num % 25 == 0)
        continue;
      final int numPrimesMask = getPrimesMask(num, primes);
      for (int primesMask = 0; primesMask < n; ++primesMask) {
        if ((primesMask & numPrimesMask) > 0)
          continue;
        final int nextPrimesMask = primesMask | numPrimesMask;
        dp[nextPrimesMask] += dp[primesMask] * count[num];
        dp[nextPrimesMask] %= MOD;
      }
    }

    return (int) (modPow(2, count[1]) * ((Arrays.stream(dp).sum() - 1) % MOD) % MOD);
  }

  private static final int MOD = 1_000_000_007;

  private int getPrimesMask(int num, int[] primes) {
    int primesMask = 0;
    for (int i = 0; i < primes.length; ++i)
      if (num % primes[i] == 0)
        primesMask |= 1 << i;
    return primesMask;
  }

  private long modPow(long x, long n) {
    if (n == 0)
      return 1;
    if (n % 2 == 1)
      return x * modPow(x, n - 1) % MOD;
    return modPow(x * x % MOD, n / 2);
  }
}

class Solution {
 public:
  int numberOfGoodSubsets(vector<int>& nums) {
    const vector<int> primes{2, 3, 5, 7, 11, 13, 17, 19, 23, 29};
    const int n = 1 << primes.size();
    const int maxNum = ranges::max(nums);
    vector<long> dp(n);
    vector<int> count(maxNum + 1);

    dp[0] = 1;

    for (const int num : nums)
      ++count[num];

    for (int num = 2; num <= maxNum; ++num) {
      if (count[num] == 0)
        continue;
      if (num % 4 == 0 || num % 9 == 0 || num % 25 == 0)
        continue;
      const int numPrimesMask = getPrimesMask(num, primes);
      for (int primesMask = 0; primesMask < n; ++primesMask) {
        if ((primesMask & numPrimesMask) > 0)
          continue;
        const int nextPrimesMask = primesMask | numPrimesMask;
        dp[nextPrimesMask] += dp[primesMask] * count[num];
        dp[nextPrimesMask] %= kMod;
      }
    }

    return modPow(2, count[1]) *
           (accumulate(dp.begin() + 1, dp.end(), 0L) % kMod) % kMod;
  }

 private:
  static constexpr int kMod = 1'000'000'007;

  int getPrimesMask(int num, const vector<int>& primes) {
    int primesMask = 0;
    for (int i = 0; i < primes.size(); ++i)
      if (num % primes[i] == 0)
        primesMask |= 1 << i;
    return primesMask;
  }

  long modPow(long x, long n) {
    if (n == 0)
      return 1;
    if (n % 2 == 1)
      return x * modPow(x % kMod, (n - 1)) % kMod;
    return modPow(x * x % kMod, (n / 2)) % kMod;
  }
};


You are given an integer array `nums`, and you can perform the following
operation any number of times on `nums`:

* Swap the positions of two elements `nums[i]` and `nums[j]` if `gcd(nums[i], nums[j]) > 1` where `gcd(nums[i], nums[j])` is the greatest common divisor of `nums[i]` and `nums[j]`.

Return `true` if it is possible to sort `nums` in non-decreasing order using
the above swap method, 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))
    self.rank = [0] * n

  def unionByRank(self, u: int, v: int) -> None:
    i = self.find(u)
    j = self.find(v)
    if i == j:
      return False
    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
    return True

  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 gcdSort(self, nums: List[int]) -> bool:
    maxNum = max(nums)
    minPrimeFactors = self._sieveEratosthenes(maxNum + 1)
    uf = UnionFind(maxNum + 1)

    for num in nums:
      for primeFactor in self._getPrimeFactors(num, minPrimeFactors):
        uf.unionByRank(num, primeFactor)

    for a, b in zip(nums, sorted(nums)):
      if uf.find(a) != uf.find(b):
        return False

    return True

  def _sieveEratosthenes(self, n: int) -> List[int]:
    minPrimeFactors = [i for i in range(n + 1)]
    for i in range(2, int(n**0.5) + 1):
      if minPrimeFactors[i] == i:
        for j in range(i * i, n, i):
          minPrimeFactors[j] = min(minPrimeFactors[j], i)
    return minPrimeFactors

  def _getPrimeFactors(self, num: int, minPrimeFactors: List[int]) -> List[int]:
    primeFactors = []
    while num > 1:
      divisor = minPrimeFactors[num]
      primeFactors.append(divisor)
      while num % divisor == 0:
        num //= divisor
    return primeFactors

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 gcdSort(int[] nums) {
    final int mx = Arrays.stream(nums).max().getAsInt();
    final int[] minPrimeFactors = sieveEratosthenes(mx + 1);
    UnionFind uf = new UnionFind(mx + 1);

    for (final int num : nums)
      for (final int primeFactor : getPrimeFactors(num, minPrimeFactors))
        uf.unionByRank(num, primeFactor);

    int[] sortedNums = nums.clone();
    Arrays.sort(sortedNums);

    for (int i = 0; i < nums.length; ++i)
      // Can't swap nums[i] with sortedNums[i].
      if (uf.find(nums[i]) != uf.find(sortedNums[i]))
        return false;

    return true;
  }

  // Gets the minimum prime factor of i, where 1 < i <= n.
  private int[] sieveEratosthenes(int n) {
    int[] minPrimeFactors = new int[n + 1];
    for (int i = 2; i <= n; ++i)
      minPrimeFactors[i] = i;
    for (int i = 2; i * i < n; ++i)
      if (minPrimeFactors[i] == i) // `i` is prime.
        for (int j = i * i; j < n; j += i)
          minPrimeFactors[j] = Math.min(minPrimeFactors[j], i);
    return minPrimeFactors;
  }

  private List<Integer> getPrimeFactors(int num, int[] minPrimeFactors) {
    List<Integer> primeFactors = new ArrayList<>();
    while (num > 1) {
      final int divisor = minPrimeFactors[num];
      primeFactors.add(divisor);
      while (num % divisor == 0)
        num /= divisor;
    }
    return primeFactors;
  }
}

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:
  bool gcdSort(vector<int>& nums) {
    const int mx = ranges::max(nums);
    const vector<int> minPrimeFactors = sieveEratosthenes(mx + 1);
    UnionFind uf(mx + 1);

    for (const int num : nums)
      for (const int primeFactor : getPrimeFactors(num, minPrimeFactors))
        uf.unionByRank(num, primeFactor);

    vector<int> sortedNums(nums);
    ranges::sort(sortedNums);

    for (int i = 0; i < nums.size(); ++i)
      // Can't swap nums[i] with sortedNums[i].
      if (uf.find(nums[i]) != uf.find(sortedNums[i]))
        return false;

    return true;
  }

 private:
  // Gets the minimum prime factor of i, where 1 < i <= n.
  vector<int> sieveEratosthenes(int n) {
    vector<int> minPrimeFactors(n + 1);
    iota(minPrimeFactors.begin() + 2, minPrimeFactors.end(), 2);
    for (int i = 2; i * i < n; ++i)
      if (minPrimeFactors[i] == i)  // `i` is prime.
        for (int j = i * i; j < n; j += i)
          minPrimeFactors[j] = min(minPrimeFactors[j], i);
    return minPrimeFactors;
  }

  vector<int> getPrimeFactors(int num, const vector<int>& minPrimeFactors) {
    vector<int> primeFactors;
    while (num > 1) {
      const int divisor = minPrimeFactors[num];
      primeFactors.push_back(divisor);
      while (num % divisor == 0)
        num /= divisor;
    }
    return primeFactors;
  }
};


The Score of Students Solving Math Expression

You are given a string `s` that contains digits `0-9`, addition symbols `'+'`,
and multiplication symbols `'*'` only, representing a valid math expression of
single digit numbers (e.g., `3+5*2`). This expression was given to `n`
elementary school students. The students were instructed to get the answer of
the expression by following this order of operations:

1. Compute multiplication, reading from left to right; Then,
2. Compute addition, reading from left to right.

You are given an integer array `answers` of length `n`, which are the
submitted answers of the students in no particular order. You are asked to
grade the `answers`, by following these rules:

* If an answer equals the correct answer of the expression, this student will be rewarded `5` points;
* Otherwise, if the answer could be interpreted as if the student applied the operators in the wrong order but had correct arithmetic, this student will be rewarded `2` points;
* Otherwise, this student will be rewarded `0` points.

Return the sum of the points of the students.

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

class Solution:
  def scoreOfStudents(self, s: str, answers: List[int]) -> int:
    n = len(s) // 2 + 1
    ans = 0
    func = {'+': operator.add, '*': operator.mul}
    dp = [[set() for j in range(n)] for _ in range(n)]

    for i in range(n):
      dp[i][i].add(int(s[i * 2]))

    for d in range(1, n):
      for i in range(n - d):
        j = i + d
        for k in range(i, j):
          op = s[k * 2 + 1]
          for a in dp[i][k]:
            for b in dp[k + 1][j]:
              res = func[op](a, b)
              if res <= 1000:
                dp[i][j].add(res)

    correctAnswer = eval(s)

    for answer, freq in collections.Counter(answers).items():
      if answer == correctAnswer:
        ans += 5 * freq
      elif answer in dp[0][n - 1]:
        ans += 2 * freq

    return ans

class Solution {
  public int scoreOfStudents(String s, int[] answers) {
    final int n = s.length() / 2 + 1;
    int ans = 0;
    Set<Integer>[][] dp = new Set[n][n];
    Map<Integer, Integer> count = new HashMap<>();

    for (int i = 0; i < n; ++i)
      for (int j = i; j < n; ++j)
        dp[i][j] = new HashSet<>();

    for (int i = 0; i < n; ++i)
      dp[i][i].add(s.charAt(i * 2) - '0');

    for (int d = 1; d < n; ++d)
      for (int i = 0; i + d < n; ++i) {
        final int j = i + d;
        for (int k = i; k < j; ++k) {
          final char op = s.charAt(k * 2 + 1);
          for (final int a : dp[i][k])
            for (final int b : dp[k + 1][j]) {
              final int res = func(op, a, b);
              if (res <= 1000)
                dp[i][j].add(res);
            }
        }
      }

    final int correctAnswer = eval(s);

    for (final int answer : answers)
      count.merge(answer, 1, Integer::sum);

    for (final int answer : count.keySet())
      if (answer == correctAnswer)
        ans += 5 * count.get(answer);
      else if (dp[0][n - 1].contains(answer))
        ans += 2 * count.get(answer);

    return ans;
  }

  private int eval(final String s) {
    int ans = 0;
    int currNum = 0;
    int prevNum = 0;
    char op = '+';

    for (int i = 0; i < s.length(); ++i) {
      final char c = s.charAt(i);
      if (Character.isDigit(c))
        currNum = currNum * 10 + (c - '0');
      if (!Character.isDigit(c) || i == s.length() - 1) {
        if (op == '+') {
          ans += prevNum;
          prevNum = currNum;
        } else if (op == '*') {
          prevNum = prevNum * currNum;
        }
        op = c;
        currNum = 0;
      }
    }

    return ans + prevNum;
  }

  private int func(char op, int a, int b) {
    if (op == '+')
      return a + b;
    return a * b;
  }
}

class Solution {
 public:
  int scoreOfStudents(string s, vector<int>& answers) {
    const int n = s.length() / 2 + 1;
    const unordered_map<char, function<int(int, int)>> func{
        {'+', plus<int>()}, {'*', multiplies<int>()}};
    int ans = 0;
    vector<vector<unordered_set<int>>> dp(n, vector<unordered_set<int>>(n));
    unordered_map<int, int> count;

    for (int i = 0; i < n; ++i)
      dp[i][i].insert(s[i * 2] - '0');

    for (int d = 1; d < n; ++d)
      for (int i = 0; i + d < n; ++i) {
        const int j = i + d;
        for (int k = i; k < j; ++k) {
          const char op = s[k * 2 + 1];
          for (const int a : dp[i][k])
            for (const int b : dp[k + 1][j]) {
              const int res = func.at(op)(a, b);
              if (res <= 1000)
                dp[i][j].insert(res);
            }
        }
      }

    const int correctAnswer = eval(s);

    for (const int answer : answers)
      ++count[answer];

    for (const auto& [answer, freq] : count)
      if (answer == correctAnswer)
        ans += 5 * freq;
      else if (dp[0][n - 1].contains(answer))
        ans += 2 * freq;

    return ans;
  }

 private:
  int eval(const string& s) {
    int ans = 0;
    int prevNum = 0;
    int currNum = 0;
    char op = '+';

    for (int i = 0; i < s.length(); ++i) {
      const char c = s[i];
      if (isdigit(c))
        currNum = currNum * 10 + (c - '0');
      if (!isdigit(c) || i == s.length() - 1) {
        if (op == '+') {
          ans += prevNum;
          prevNum = currNum;
        } else if (op == '*') {
          prevNum = prevNum * currNum;
        }
        op = c;
        currNum = 0;
      }
    }

    return ans + prevNum;
  }
};


Smallest K-Length Subsequence With Occurrences of a Letter

You are given a string `s`, an integer `k`, a letter `letter`, and an integer
`repetition`.

Return the lexicographically smallest subsequence of `s` of length `k` that
has the letter `letter` appear at least `repetition` times. The test cases are
generated so that the `letter` appears in `s` at least `repetition` times.

A subsequence is a string that can be derived from another string by deleting
some or no characters without changing the order of the remaining characters.

A string `a` is lexicographically smaller than a string `b` if in the first
position where `a` and `b` differ, string `a` has a letter that appears
earlier in the alphabet than the corresponding letter in `b`.

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 smallestSubsequence(self, s: str, k: int, letter: str, repetition: int) -> str:
    stack = []
    required = repetition
    nLetters = s.count(letter)

    for i, c in enumerate(s):
      while stack and stack[-1] > c  and len(stack) + len(s) - i - 1 >= k and (stack[-1] != letter or nLetters > required):
        if stack.pop() == letter:
          required += 1
      if len(stack) < k:
        if c == letter:
          stack.append(c)
          required -= 1
        elif k - len(stack) > required:
          stack.append(c)
      if c == letter:
        nLetters -= 1

    return ''.join(stack)

class Solution {
  public String smallestSubsequence(String s, int k, char letter, int repetition) {
    StringBuilder sb = new StringBuilder();
    Deque<Character> stack = new ArrayDeque<>();
    int required = repetition;
    int nLetters = (int) s.chars().filter(c -> c == letter).count();

    for (int i = 0; i < s.length(); ++i) {
      final char c = s.charAt(i);
      while (!stack.isEmpty() && stack.peek() > c && stack.size() + s.length() - i - 1 >= k &&
             (stack.peek() != letter || nLetters > required))
        if (stack.pop() == letter)
          ++required;
      if (stack.size() < k)
        if (c == letter) {
          stack.push(c);
          --required;
        } else if (k - stack.size() > required) {
          stack.push(c);
        }
      if (c == letter)
        --nLetters;
    }

    for (final char c : stack)
      sb.append(c);

    return sb.reverse().toString();
  }
}

class Solution {
 public:
  string smallestSubsequence(string s, int k, char letter, int repetition) {
    string ans;
    vector<char> stack;
    int required = repetition;
    int nLetters = ranges::count(s, letter);

    for (int i = 0; i < s.length(); ++i) {
      const char c = s[i];
      while (!stack.empty() && stack.back() > c &&
             stack.size() + s.length() - i - 1 >= k &&
             (stack.back() != letter || nLetters > required)) {
        const char popped = stack.back();
        stack.pop_back();
        if (popped == letter)
          ++required;
      }
      if (stack.size() < k)
        if (c == letter) {
          stack.push_back(c);
          --required;
        } else if (k > stack.size() + required) {
          stack.push_back(c);
        }
      if (c == letter)
        --nLetters;
    }

    for (const char c : stack)
      ans += c;

    return ans;
  }
};


Kth Smallest Product of Two Sorted Arrays

Given two sorted 0-indexed integer arrays `nums1` and `nums2` as well as an
integer `k`, return the `kth` (1-based) smallest product of `nums1[i] *
nums2[j]` where `0 <= i < nums1.length` and `0 <= j < nums2.length`.

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 kthSmallestProduct(self, nums1: List[int], nums2: List[int], k: int) -> int:
    A1 = [-num for num in nums1 if num < 0][::-1]
    A2 = [num for num in nums1 if num >= 0]
    B1 = [-num for num in nums2 if num < 0][::-1]
    B2 = [num for num in nums2 if num >= 0]

    negCount = len(A1) * len(B2) + len(A2) * len(B1)

    if k > negCount:
      k -= negCount
      sign = 1
    else:
      k = negCount - k + 1
      sign = -1
      B1, B2 = B2, B1

    def numProductNoGreaterThan(A: List[int], B: List[int], m: int) -> int:
      ans = 0
      j = len(B) - 1
      for i in range(len(A)):
        while j >= 0 and A[i] * B[j] > m:
          j -= 1
        ans += j + 1
      return ans

    l = 0
    r = 10**10

    while l < r:
      m = (l + r) // 2
      if numProductNoGreaterThan(A1, B1, m) + numProductNoGreaterThan(A2, B2, m) >= k:
        r = m
      else:
        l = m + 1

    return sign * l

class Solution {
  public long kthSmallestProduct(int[] nums1, int[] nums2, long k) {
    List<Integer> A1 = new ArrayList<>();
    List<Integer> A2 = new ArrayList<>();
    List<Integer> B1 = new ArrayList<>();
    List<Integer> B2 = new ArrayList<>();

    seperate(nums1, A1, A2);
    seperate(nums2, B1, B2);

    final long negCount = A1.size() * B2.size() + A2.size() * B1.size();
    int sign = 1;

    if (k > negCount) {
      k -= negCount; //  Find the (k - negCount)-th positive.
    } else {
      k = negCount - k + 1; // Find the (negCount - k + 1)-th abs(negative).
      sign = -1;
      List<Integer> temp = B1;
      B1 = B2;
      B2 = temp;
    }

    long l = 0;
    long r = (long) 1e10;

    while (l < r) {
      final long m = (l + r) / 2;
      if (numProductNoGreaterThan(A1, B1, m) + numProductNoGreaterThan(A2, B2, m) >= k)
        r = m;
      else
        l = m + 1;
    }

    return sign * l;
  }

  private void seperate(int[] arr, List<Integer> A1, List<Integer> A2) {
    for (final int a : arr)
      if (a < 0)
        A1.add(-a);
      else
        A2.add(a);
    Collections.reverse(A1); // Reverse to sort ascending
  }

  private long numProductNoGreaterThan(List<Integer> A, List<Integer> B, long m) {
    long count = 0;
    int j = B.size() - 1;
    // For each a, find the first index j s.t. a * B[j] <= m
    // So numProductNoGreaterThan m for this row will be j + 1
    for (final long a : A) {
      while (j >= 0 && a * B.get(j) > m)
        --j;
      count += j + 1;
    }
    return count;
  }
}

class Solution {
 public:
  long long kthSmallestProduct(vector<int>& nums1, vector<int>& nums2,
                               long long k) {
    vector<int> A1;
    vector<int> A2;
    vector<int> B1;
    vector<int> B2;

    seperate(nums1, A1, A2);
    seperate(nums2, B1, B2);

    const long negCount = A1.size() * B2.size() + A2.size() * B1.size();
    int sign = 1;

    if (k > negCount) {
      k -= negCount;  //  Find the (k - negCount)-th positive.
    } else {
      k = negCount - k + 1;  // Find the (negCount - k + 1)-th abs(negative).
      sign = -1;
      swap(B1, B2);
    }

    long l = 0;
    long r = 1e10;

    while (l < r) {
      const long m = (l + r) / 2;
      if (numProductNoGreaterThan(A1, B1, m) +
              numProductNoGreaterThan(A2, B2, m) >=
          k)
        r = m;
      else
        l = m + 1;
    }

    return sign * l;
  }

 private:
  void seperate(const vector<int>& arr, vector<int>& A1, vector<int>& A2) {
    for (const int a : arr)
      if (a < 0)
        A1.push_back(-a);
      else
        A2.push_back(a);
    ranges::reverse(A1);  // Reverse to sort ascending
  }

  long numProductNoGreaterThan(const vector<int>& A, const vector<int>& B,
                               long m) {
    long count = 0;
    int j = B.size() - 1;
    // For each a, find the first index j s.t. a * B[j] <= m
    // So numProductNoGreaterThan m for this row will be j + 1
    for (const long a : A) {
      while (j >= 0 && a * B[j] > m)
        --j;
      count += j + 1;
    }
    return count;
  }
};


Second Minimum Time to Reach Destination

A city is represented as a bi-directional connected graph with `n` vertices
where each vertex is labeled from `1` to `n` (inclusive). The edges in the
graph are represented as a 2D integer array `edges`, where each `edges[i] =
[ui, vi]` denotes a bi-directional edge between vertex `ui` and vertex `vi`.
Every vertex pair is connected by at most one edge, and no vertex has an edge
to itself. The time taken to traverse any edge is `time` minutes.

Each vertex has a traffic signal which changes its color from green to red and
vice versa every `change` minutes. All signals change at the same time. You
can enter a vertex at any time, but can leave a vertex only when the signal is
green. You cannot wait at a vertex if the signal is green.

The second minimum value is defined as the smallest value strictly larger than
the minimum value.

* For example the second minimum value of `[2, 3, 4]` is `3`, and the second minimum value of `[2, 2, 4]` is `4`.

Given `n`, `edges`, `time`, and `change`, return the second minimum time it
will take to go from vertex `1` to vertex `n`.

Notes:

* You can go through any vertex any number of times, including `1` and `n`.
* You can assume that when the journey starts, all signals have just turned green.

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 secondMinimum(self, n: int, edges: List[List[int]], time: int, change: int) -> int:
    graph = [[] for _ in range(n + 1)]
    q = collections.deque([(1, 0)])
    minTime = [[math.inf] * 2 for _ in range(n + 1)]
    minTime[1][0] = 0

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

    while q:
      i, prevTime = q.popleft()

      numChangeSignal = prevTime // change
      waitTime = change - (prevTime % change) if numChangeSignal & 1 else 0
      newTime = prevTime + waitTime + time
      for j in graph[i]:
        if newTime < minTime[j][0]:
          minTime[j][0] = newTime
          q.append((j, newTime))
        elif minTime[j][0] < newTime < minTime[j][1]:
          if j == n:
            return newTime
          minTime[j][1] = newTime
          q.append((j, newTime))

class Solution {
  public int secondMinimum(int n, int[][] edges, int time, int change) {
    List<Integer>[] graph = new List[n + 1];
    // (index, time)
    Queue<Pair<Integer, Integer>> q = new ArrayDeque<>(List.of(new Pair<>(1, 0)));
    // minTime[u][0] := the first minimum time to reach the node u
    // minTime[u][1] := the second minimum time to reach the node u
    int[][] minTime = new int[n + 1][2];
    Arrays.stream(minTime).forEach(A -> Arrays.fill(A, Integer.MAX_VALUE));
    minTime[1][0] = 0;

    for (int i = 1; i <= n; ++i)
      graph[i] = new ArrayList<>();

    for (int[] edge : edges) {
      final int u = edge[0];
      final int v = edge[1];
      graph[u].add(v);
      graph[v].add(u);
    }

    while (!q.isEmpty()) {
      final int u = q.peek().getKey();
      final int prevTime = q.poll().getValue();
      // Start from green.
      // If `numChangeSignal` is odd, now red.
      // If `numChangeSignal` is even, now green.
      final int numChangeSignal = prevTime / change;
      final int waitTime = numChangeSignal % 2 == 0 ? 0 : change - prevTime % change;
      final int newTime = prevTime + waitTime + time;
      for (final int v : graph[u])
        if (newTime < minTime[v][0]) {
          minTime[v][0] = newTime;
          q.offer(new Pair<>(v, newTime));
        } else if (minTime[v][0] < newTime && newTime < minTime[v][1]) {
          if (v == n)
            return newTime;
          minTime[v][1] = newTime;
          q.offer(new Pair<>(v, newTime));
        }
    }

    throw new IllegalArgumentException();
  }
}

class Solution {
 public:
  int secondMinimum(int n, vector<vector<int>>& edges, int time, int change) {
    vector<vector<int>> graph(n + 1);
    queue<pair<int, int>> q{{{1, 0}}};
    // minTime[u][0] := the first minimum time to reach the node u
    // minTime[u][1] := the second minimum time to reach the node u
    vector<vector<int>> minTime(n + 1, vector<int>(2, INT_MAX));
    minTime[1][0] = 0;

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

    while (!q.empty()) {
      const auto [u, prevTime] = q.front();
      q.pop();
      // Start from green.
      // If `numChangeSignal` is odd, now red.
      // If `numChangeSignal` is even, now green.
      const int numChangeSignal = prevTime / change;
      const int waitTime =
          numChangeSignal % 2 == 0 ? 0 : change - prevTime % change;
      const int newTime = prevTime + waitTime + time;
      for (const int v : graph[u])
        if (newTime < minTime[v][0]) {
          minTime[v][0] = newTime;
          q.emplace(v, newTime);
        } else if (minTime[v][0] < newTime && newTime < minTime[v][1]) {
          if (v == n)
            return newTime;
          minTime[v][1] = newTime;
          q.emplace(v, newTime);
        }
    }

    throw;
  }
};


You are given a 0-indexed integer array `nums` containing distinct numbers, an
integer `start`, and an integer `goal`. There is an integer `x` that is
initially set to `start`, and you want to perform operations on `x` such that
it is converted to `goal`. You can perform the following operation repeatedly
on the number `x`:

If `0 <= x <= 1000`, then for any index `i` in the array (`0 <= i <
nums.length`), you can set `x` to any of the following:

* `x + nums[i]`
* `x - nums[i]`
* `x ^ nums[i]` (bitwise-XOR)

Note that you can use each `nums[i]` any number of times in any order.
Operations that set `x` to be out of the range `0 <= x <= 1000` are valid, but
no more operations can be done afterward.

Return the minimum number of operations needed to convert `x = start` into
`goal`, and `-1` if it is not possible.

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 minimumOperations(self, nums: List[int], start: int, goal: int) -> int:
    ans = 0
    q = collections.deque([start])
    seen = {start}

    while q:
      ans += 1
      for _ in range(len(q)):
        x = q.popleft()
        for num in nums:
          for res in (x + num, x - num, x ^ num):
            if res == goal:
              return ans
            if res < 0 or res > 1000 or res in seen:
              continue
            seen.add(res)
            q.append(res)

    return -1

class Solution {
  public int minimumOperations(int[] nums, int start, int goal) {
    Queue<Integer> q = new ArrayDeque<>(List.of(start));
    boolean[] seen = new boolean[1001];
    seen[start] = true;

    for (int step = 1; !q.isEmpty(); ++step)
      for (int sz = q.size(); sz > 0; --sz) {
        final int x = q.poll();
        for (final int num : nums) {
          for (final int res : new int[] {x + num, x - num, x ^ num}) {
            if (res == goal)
              return step;
            if (res < 0 || res > 1000 || seen[res])
              continue;
            seen[res] = true;
            q.offer(res);
          }
        }
      }

    return -1;
  }
}

class Solution {
 public:
  int minimumOperations(vector<int>& nums, int start, int goal) {
    queue<int> q{{start}};
    vector<bool> seen(1001);
    seen[start] = true;

    for (int step = 1; !q.empty(); ++step)
      for (int sz = q.size(); sz > 0; --sz) {
        const int x = q.front();
        q.pop();
        for (const int num : nums) {
          for (const int res : {x + num, x - num, x ^ num}) {
            if (res == goal)
              return step;
            if (res < 0 || res > 1000 || seen[res])
              continue;
            seen[res] = true;
            q.push(res);
          }
        }
      }

    return -1;
  }
};


You are given an integer `n` indicating the number of people in a network.
Each person is labeled from `0` to `n - 1`.

You are also given a 0-indexed 2D integer array `restrictions`, where
`restrictions[i] = [xi, yi]` means that person `xi` and person `yi` cannot
become friends, either directly or indirectly through other people.

Initially, no one is friends with each other. You are given a list of friend
requests as a 0-indexed 2D integer array `requests`, where `requests[j] = [uj,
vj]` is a friend request between person `uj` and person `vj`.

A friend request is successful if `uj` and `vj` can be friends. Each friend
request is processed in the given order (i.e., `requests[j]` occurs before
`requests[j + 1]`), and upon a successful request, `uj` and `vj` become direct
friends for all future friend requests.

Return a boolean array `result`, where each `result[j]` is `true` if the `jth`
friend request is successful or `false` if it is not.

Note: If `uj` and `vj` are already direct friends, the request is still
successful.

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 friendRequests(self, n: int, restrictions: List[List[int]], requests: List[List[int]]) -> List[bool]:
    ans = []
    uf = UnionFind(n)

    for u, v in requests:
      pu = uf.find(u)
      pv = uf.find(v)
      isValid = True
      if pu != pv:
        for x, y in restrictions:
          px = uf.find(x)
          py = uf.find(y)
          if (pu, pv) in [(px, py), (py, px)]:
            isValid = False
            break
      ans.append(isValid)
      if isValid:
        uf.unionByRank(pu, pv)

    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 boolean[] friendRequests(int n, int[][] restrictions, int[][] requests) {
    boolean[] ans = new boolean[requests.length];
    UnionFind uf = new UnionFind(n);

    for (int i = 0; i < requests.length; ++i) {
      final int pu = uf.find(requests[i][0]);
      final int pv = uf.find(requests[i][1]);
      boolean isValid = true;
      if (pu != pv)
        for (int[] restriction : restrictions) {
          final int px = uf.find(restriction[0]);
          final int py = uf.find(restriction[1]);
          if (pu == px && pv == py || pu == py && pv == px) {
            isValid = false;
            break;
          }
        }
      ans[i] = isValid;
      if (isValid)
        uf.unionByRank(pu, pv);
    }

    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:
  vector<bool> friendRequests(int n, vector<vector<int>>& restrictions,
                              vector<vector<int>>& requests) {
    vector<bool> ans;
    UnionFind uf(n);

    for (const vector<int>& request : requests) {
      const int i = uf.find(request[0]);
      const int j = uf.find(request[1]);
      bool isValid = true;
      if (i != j)
        for (const vector<int>& restriction : restrictions) {
          const int x = uf.find(restriction[0]);
          const int y = uf.find(restriction[1]);
          if (i == x && j == y || i == y && j == x) {
            isValid = false;
            break;
          }
        }
      ans.push_back(isValid);
      if (isValid)
        uf.unionByRank(i, j);
    }

    return ans;
  }
};


Minimum Number of Buckets Required to Collect Rainwater from Houses

You are given a 0-indexed string `hamsters` where `hamsters[i]` is either:

* `'H'` indicating that there is a hamster at index `i`, or
* `'.'` indicating that index `i` is empty.

You will add some number of food buckets at the empty indices in order to feed
the hamsters. A hamster can be fed if there is at least one food bucket to its
left or to its right. More formally, a hamster at index `i` can be fed if you
place a food bucket at index `i - 1` and/or at index `i + 1`.

Return the minimum number of food buckets you should place at empty indices to
feed all the hamsters or `-1` if it is impossible to feed all of them.

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 minimumBuckets(self, street: str) -> int:
    A = list(street)

    for i, c in enumerate(A):
      if c == 'H':
        if i > 0 and A[i - 1] == 'B':
          continue
        if i + 1 < len(A) and A[i + 1] == '.':
          A[i + 1] = 'B'
        elif i > 0 and A[i - 1] == '.':
          A[i - 1] = 'B'
        else:
          return -1

    return A.count('B')

class Solution {
  public int minimumBuckets(String street) {
    final char[] A = street.toCharArray();

    for (int i = 0; i < A.length; ++i)
      if (A[i] == 'H') {
        if (i > 0 && A[i - 1] == 'B')
          continue;
        if (i + 1 < A.length && A[i + 1] == '.')
          // Always prefer place a bucket in (i + 1) because it enhances the
          // possibility to collect the upcoming houses.
          A[i + 1] = 'B';
        else if (i > 0 && A[i - 1] == '.')
          A[i - 1] = 'B';
        else
          return -1;
      }

    return (int) new String(A).chars().filter(a -> a == 'B').count();
  }
}

class Solution {
 public:
  int minimumBuckets(string street) {
    for (int i = 0; i < street.length(); ++i)
      if (street[i] == 'H') {
        if (i > 0 && street[i - 1] == 'B')
          continue;
        if (i + 1 < street.length() && street[i + 1] == '.')
          // Always prefer place a bucket in (i + 1) because it enhances the
          // possibility to collect the upcoming houses.
          street[i + 1] = 'B';
        else if (i > 0 && street[i - 1] == '.')
          street[i - 1] = 'B';
        else
          return -1;
      }

    return ranges::count(street, 'B');
  }
};


You are given an integer `n` indicating there are `n` people numbered from `0`
to `n - 1`. You are also given a 0-indexed 2D integer array `meetings` where
`meetings[i] = [xi, yi, timei]` indicates that person `xi` and person `yi`
have a meeting at `timei`. A person may attend multiple meetings at the same
time. Finally, you are given an integer `firstPerson`.

Person `0` has a secret and initially shares the secret with a person
`firstPerson` at time `0`. This secret is then shared every time a meeting
takes place with a person that has the secret. More formally, for every
meeting, if a person `xi` has the secret at `timei`, then they will share the
secret with person `yi`, and vice versa.

The secrets are shared instantaneously. That is, a person may receive the
secret and share it with people in other meetings within the same time frame.

Return a list of all the people that have the secret after all the meetings
have taken place. You may return the answer in any order.

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 connected(self, u: int, v: int) -> bool:
    return self._find(self.id[u]) == self._find(self.id[v])

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

  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 findAllPeople(self, n: int, meetings: List[List[int]], firstPerson: int) -> List[int]:
    uf = UnionFind(n)
    timeToPairs = collections.defaultdict(list)

    uf.unionByRank(0, firstPerson)

    for x, y, time in meetings:
      timeToPairs[time].append((x, y))

    for _, pairs in sorted(timeToPairs.items(), key=lambda x: x[0]):
      peopleUnioned = set()
      for x, y in pairs:
        uf.unionByRank(x, y)
        peopleUnioned.add(x)
        peopleUnioned.add(y)
      for person in peopleUnioned:
        if not uf.connected(person, 0):
          uf.reset(person)

    res=[]
    for i in range(n):
      if uf.connected(i, 0):
        res.append(i)
    return res

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 boolean connected(int u, int v) {
    return find(u) == find(v);
  }

  public void reset(int u) {
    id[u] = u;
  }

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

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

class Solution {
  public List<Integer> findAllPeople(int n, int[][] meetings, int firstPerson) {
    List<Integer> ans = new ArrayList<>();
    UnionFind uf = new UnionFind(n);
    TreeMap<Integer, List<Pair<Integer, Integer>>> timeToPairs = new TreeMap<>();

    uf.unionByRank(0, firstPerson);

    for (int[] meeting : meetings) {
      final int x = meeting[0];
      final int y = meeting[1];
      final int time = meeting[2];
      timeToPairs.putIfAbsent(time, new ArrayList<>());
      timeToPairs.get(time).add(new Pair<>(x, y));
    }

    for (List<Pair<Integer, Integer>> pairs : timeToPairs.values()) {
      Set<Integer> peopleUnioned = new HashSet<>();
      for (Pair<Integer, Integer> pair : pairs) {
        final int x = pair.getKey();
        final int y = pair.getValue();
        uf.unionByRank(x, y);
        peopleUnioned.add(x);
        peopleUnioned.add(y);
      }
      for (final int person : peopleUnioned)
        if (!uf.connected(person, 0))
          uf.reset(person);
    }

    for (int i = 0; i < n; ++i)
      if (uf.connected(i, 0))
        ans.add(i);

    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];
    }
  }

  bool connected(int u, int v) {
    return find(u) == find(v);
  }

  void reset(int u) {
    id[u] = u;
  }

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

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

class Solution {
 public:
  vector<int> findAllPeople(int n, vector<vector<int>>& meetings,
                            int firstPerson) {
    vector<int> ans;
    UnionFind uf(n);
    map<int, vector<pair<int, int>>> timeToPairs;

    uf.unionByRank(0, firstPerson);

    for (const vector<int>& meeting : meetings) {
      const int x = meeting[0];
      const int y = meeting[1];
      const int time = meeting[2];
      timeToPairs[time].push_back({x, y});
    }

    for (const auto& [_, pairs] : timeToPairs) {
      unordered_set<int> peopleUnioned;
      for (const auto& [x, y] : pairs) {
        uf.unionByRank(x, y);
        peopleUnioned.insert(x);
        peopleUnioned.insert(y);
      }
      for (const int person : peopleUnioned)
        if (!uf.connected(person, 0))
          uf.reset(person);
    }

    for (int i = 0; i < n; ++i)
      if (uf.connected(i, 0))
        ans.push_back(i);

    return ans;
  }
};


Find All Possible Recipes from Given Supplies

You have information about `n` different recipes. You are given a string array
`recipes` and a 2D string array `ingredients`. The `ith` recipe has the name
`recipes[i]`, and you can create it if you have all the needed ingredients
from `ingredients[i]`. Ingredients to a recipe may need to be created from
other recipes, i.e., `ingredients[i]` may contain a string that is in
`recipes`.

You are also given a string array `supplies` containing all the ingredients
that you initially have, and you have an infinite supply of all of them.

Return a list of all the recipes that you can create. You may return the
answer in any order.

Note that two recipes may contain each other in their ingredients.

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 findAllRecipes(self, recipes: List[str], ingredients: List[List[str]], supplies: List[str]) -> List[str]:
    ans = []
    supplies = set(supplies)
    graph = collections.defaultdict(list)
    inDegrees = collections.Counter()
    q = collections.deque()

    for i, recipe in enumerate(recipes):
      for ingredient in ingredients[i]:
        if ingredient not in supplies:
          graph[ingredient].append(recipe)
          inDegrees[recipe] += 1

    for recipe in recipes:
      if inDegrees[recipe] == 0:
        q.append(recipe)

    while q:
      u = q.popleft()
      ans.append(u)
      for v in graph[u]:
        inDegrees[v] -= 1
        if inDegrees[v] == 0:
          q.append(v)

    return ans

class Solution {
  public List<String> findAllRecipes(String[] recipes, List<List<String>> ingredients,
                                     String[] supplies) {
    List<String> ans = new ArrayList<>();
    Set<String> suppliesSet = new HashSet<>();
    for (final String supply : supplies)
      suppliesSet.add(supply);
    Map<String, List<String>> graph = new HashMap<>();
    Map<String, Integer> inDegrees = new HashMap<>();

    // Build the graph.
    for (int i = 0; i < recipes.length; ++i)
      for (final String ingredient : ingredients.get(i))
        if (!suppliesSet.contains(ingredient)) {
          graph.putIfAbsent(ingredient, new ArrayList<>());
          graph.get(ingredient).add(recipes[i]);
          inDegrees.merge(recipes[i], 1, Integer::sum);
        }

    // Perform topological sorting.
    Queue<String> q = Arrays.stream(recipes)
                          .filter(recipe -> inDegrees.getOrDefault(recipe, 0) == 0)
                          .collect(Collectors.toCollection(ArrayDeque::new));

    while (!q.isEmpty()) {
      final String u = q.poll();
      ans.add(u);
      if (!graph.containsKey(u))
        continue;
      for (final String v : graph.get(u)) {
        inDegrees.merge(v, -1, Integer::sum);
        if (inDegrees.get(v) == 0)
          q.offer(v);
      }
    }

    return ans;
  }
}

class Solution {
 public:
  vector<string> findAllRecipes(vector<string>& recipes,
                                vector<vector<string>>& ingredients,
                                vector<string>& supplies) {
    vector<string> ans;
    unordered_set<string> suppliesSet(supplies.begin(), supplies.end());
    unordered_map<string, vector<string>> graph;
    unordered_map<string, int> inDegrees;
    queue<string> q;

    // Build the graph.
    for (int i = 0; i < recipes.size(); ++i)
      for (const string& ingredient : ingredients[i])
        if (!suppliesSet.contains(ingredient)) {
          graph[ingredient].push_back(recipes[i]);
          ++inDegrees[recipes[i]];
        }

    // Perform topological sorting.
    for (const string& recipe : recipes)
      if (!inDegrees.contains(recipe))
        q.push(recipe);

    while (!q.empty()) {
      const string u = q.front();
      q.pop();
      ans.push_back(u);
      if (!graph.contains(u))
        continue;
      for (const string& v : graph[u])
        if (--inDegrees[v] == 0)
          q.push(v);
    }

    return ans;
  }
};


Maximum Employees to Be Invited to a Meeting

A company is organizing a meeting and has a list of `n` employees, waiting to
be invited. They have arranged for a large circular table, capable of seating
any number of employees.

The employees are numbered from `0` to `n - 1`. Each employee has a favorite
person and they will attend the meeting only if they can sit next to their
favorite person at the table. The favorite person of an employee is not
themself.

Given a 0-indexed integer array `favorite`, where `favorite[i]` denotes the
favorite person of the `ith` employee, return the maximum number of employees
that can be invited to the meeting.

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 State(Enum):
  kInit = 0
  kVisiting = 1
  kVisited = 2

class Solution:
  def maximumInvitations(self, favorite: List[int]) -> int:
    n = len(favorite)
    sumComponentsLength = 0
    graph = [[] for _ in range(n)]
    inDegrees = [0] * n
    maxChainLength = [1] * n

    for i, f in enumerate(favorite):
      graph[i].append(f)
      inDegrees[f] += 1

    q = collections.deque([i for i, d in enumerate(inDegrees) if d == 0])

    while q:
      u = q.popleft()
      for v in graph[u]:
        inDegrees[v] -= 1
        if inDegrees[v] == 0:
          q.append(v)
        maxChainLength[v] = max(maxChainLength[v], 1 + maxChainLength[u])

    for i in range(n):
      if favorite[favorite[i]] == i:
        sumComponentsLength += maxChainLength[i] + maxChainLength[favorite[i]]

    maxCycleLength = 0
    parent = [-1] * n
    seen = set()
    states = [State.kInit] * n

    def findCycle(u: int) -> None:
      nonlocal maxCycleLength
      seen.add(u)
      states[u] = State.kVisiting
      for v in graph[u]:
        if v not in seen:
          parent[v] = u
          findCycle(v)
        elif states[v] == State.kVisiting:
          curr = u
          cycleLength = 1
          while curr != v:
            curr = parent[curr]
            cycleLength += 1
          maxCycleLength = max(maxCycleLength, cycleLength)
      states[u] = State.kVisited

    for i in range(n):
      if i not in seen:
        findCycle(i)

    return max(sumComponentsLength // 2, maxCycleLength)

enum State { INIT, VISITING, VISITED }

class Solution {
  public int maximumInvitations(int[] favorite) {
    final int n = favorite.length;
    int sumComponentsLength = 0; // the component: a -> b -> c <-> x <- y
    List<Integer>[] graph = new List[n];
    int[] inDegrees = new int[n];
    int[] maxChainLength = new int[n];
    Arrays.fill(maxChainLength, 1);
    Arrays.setAll(graph, i -> new ArrayList<>());

    // Build the graph.
    for (int i = 0; i < n; ++i) {
      graph[i].add(favorite[i]);
      ++inDegrees[favorite[i]];
    }

    // Perform topological sorting.
    Queue<Integer> q = IntStream.range(0, n)
                           .filter(i -> inDegrees[i] == 0)
                           .boxed()
                           .collect(Collectors.toCollection(ArrayDeque::new));

    while (!q.isEmpty()) {
      final int u = q.poll();
      for (final int v : graph[u]) {
        if (--inDegrees[v] == 0)
          q.offer(v);
        maxChainLength[v] = Math.max(maxChainLength[v], 1 + maxChainLength[u]);
      }
    }

    for (int i = 0; i < n; ++i)
      if (favorite[favorite[i]] == i)
        // i <-> favorite[i] (the cycle's length = 2)
        sumComponentsLength += maxChainLength[i] + maxChainLength[favorite[i]];

    int[] parent = new int[n];
    Arrays.fill(parent, -1);
    boolean[] seen = new boolean[n];
    State[] states = new State[n];

    for (int i = 0; i < n; ++i)
      if (!seen[i])
        findCycle(graph, i, parent, seen, states);

    return Math.max(sumComponentsLength / 2, maxCycleLength);
  }

  private int maxCycleLength = 0; // the cycle : a -> b -> c -> a

  private void findCycle(List<Integer>[] graph, int u, int[] parent, boolean[] seen,
                         State[] states) {
    seen[u] = true;
    states[u] = State.VISITING;

    for (final int v : graph[u]) {
      if (!seen[v]) {
        parent[v] = u;
        findCycle(graph, v, parent, seen, states);
      } else if (states[v] == State.VISITING) {
        // Find the cycle's length.
        int curr = u;
        int cycleLength = 1;
        while (curr != v) {
          curr = parent[curr];
          ++cycleLength;
        }
        maxCycleLength = Math.max(maxCycleLength, cycleLength);
      }
    }

    states[u] = State.VISITED;
  }
}

enum class State { kInit, kVisiting, kVisited };

class Solution {
 public:
  int maximumInvitations(vector<int>& favorite) {
    const int n = favorite.size();
    int sumComponentsLength = 0;  // the component: a -> b -> c <-> x <- y
    vector<vector<int>> graph(n);
    vector<int> inDegrees(n);
    vector<int> maxChainLength(n, 1);
    queue<int> q;

    // Build the graph.
    for (int i = 0; i < n; ++i) {
      graph[i].push_back(favorite[i]);
      ++inDegrees[favorite[i]];
    }

    // Perform topological sorting.
    for (int i = 0; i < n; ++i)
      if (inDegrees[i] == 0)
        q.push(i);

    while (!q.empty()) {
      const int u = q.front();
      q.pop();
      for (const int v : graph[u]) {
        if (--inDegrees[v] == 0)
          q.push(v);
        maxChainLength[v] = max(maxChainLength[v], 1 + maxChainLength[u]);
      }
    }

    for (int i = 0; i < n; ++i)
      if (favorite[favorite[i]] == i)
        // i <-> favorite[i] (the cycle's length = 2)
        sumComponentsLength += maxChainLength[i] + maxChainLength[favorite[i]];

    int maxCycleLength = 0;  // the cycle : a -> b -> c -> a
    vector<int> parent(n, -1);
    vector<bool> seen(n);
    vector<State> states(n);

    for (int i = 0; i < n; ++i)
      if (!seen[i])
        findCycle(graph, i, parent, seen, states, maxCycleLength);

    return max(sumComponentsLength / 2, maxCycleLength);
  }

 private:
  void findCycle(const vector<vector<int>>& graph, int u, vector<int>& parent,
                 vector<bool>& seen, vector<State>& states,
                 int& maxCycleLength) {
    seen[u] = true;
    states[u] = State::kVisiting;

    for (const int v : graph[u]) {
      if (!seen[v]) {
        parent[v] = u;
        findCycle(graph, v, parent, seen, states, maxCycleLength);
      } else if (states[v] == State::kVisiting) {
        // Find the cycle's length.
        int curr = u;
        int cycleLength = 1;
        while (curr != v) {
          curr = parent[curr];
          ++cycleLength;
        }
        maxCycleLength = max(maxCycleLength, cycleLength);
      }
    }

    states[u] = State::kVisited;
  }
};


You are given an `m x n` binary matrix `grid` where each cell is either `0`
(empty) or `1` (occupied).

You are then given stamps of size `stampHeight x stampWidth`. We want to fit
the stamps such that they follow the given restrictions and requirements:

1. Cover all the empty cells.
2. Do not cover any of the occupied cells.
3. We can put as many stamps as we want.
4. Stamps can overlap with each other.
5. Stamps are not allowed to be rotated.
6. Stamps must stay completely inside the grid.

Return `true` if it is possible to fit the stamps while following the given
restrictions and requirements. Otherwise, return `false`.

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 possibleToStamp(self, grid: List[List[int]], stampHeight: int, stampWidth: int) -> bool:
    m = len(grid)
    n = len(grid[0])
    A = [[0] * (n + 1) for _ in range(m + 1)]
    B = [[0] * (n + 1) for _ in range(m + 1)]
    fit = [[False] * n for _ in range(m)]

    for i in range(m):
      for j in range(n):
        A[i + 1][j + 1] = A[i + 1][j] + A[i][j + 1] - A[i][j] + grid[i][j]
        if i + 1 >= stampHeight and j + 1 >= stampWidth:
          x = i - stampHeight + 1
          y = j - stampWidth + 1
          if A[i + 1][j + 1] - A[x][j + 1] - A[i + 1][y] + A[x][y] == 0:
            fit[i][j] = True

    for i in range(m):
      for j in range(n):
        B[i + 1][j + 1] = B[i + 1][j] + B[i][j + 1] - B[i][j] + fit[i][j]

    for i in range(m):
      for j in range(n):
        if not grid[i][j]:
          x = min(i + stampHeight, m)
          y = min(j + stampWidth, n)
          if B[x][y] - B[i][y] - B[x][j] + B[i][j] == 0:
            return False

    return True

class Solution {
  public boolean possibleToStamp(int[][] grid, int stampHeight, int stampWidth) {
    final int m = grid.length;
    final int n = grid[0].length;
    // A[i][j] := the number of 1s in grid[0..i)[0..j)
    int[][] A = new int[m + 1][n + 1];
    // B[i][j] := the number of ways to stamp the submatrix in [0..i)[0..j)
    int[][] B = new int[m + 1][n + 1];
    // fit[i][j] := 1 if the stamps can fit with the right-bottom at (i, j)
    int[][] fit = new int[m][n];

    for (int i = 0; i < m; ++i)
      for (int j = 0; j < n; ++j) {
        A[i + 1][j + 1] = A[i + 1][j] + A[i][j + 1] - A[i][j] + grid[i][j];
        if (i + 1 >= stampHeight && j + 1 >= stampWidth) {
          final int x = i - stampHeight + 1;
          final int y = j - stampWidth + 1;
          if (A[i + 1][j + 1] - A[x][j + 1] - A[i + 1][y] + A[x][y] == 0)
            fit[i][j] = 1;
        }
      }

    for (int i = 0; i < m; ++i)
      for (int j = 0; j < n; ++j)
        B[i + 1][j + 1] = B[i + 1][j] + B[i][j + 1] - B[i][j] + fit[i][j];

    for (int i = 0; i < m; ++i)
      for (int j = 0; j < n; ++j)
        if (grid[i][j] == 0) {
          final int x = Math.min(i + stampHeight, m);
          final int y = Math.min(j + stampWidth, n);
          if (B[x][y] - B[i][y] - B[x][j] + B[i][j] == 0)
            return false;
        }

    return true;
  }
}

class Solution {
 public:
  bool possibleToStamp(vector<vector<int>>& grid, int stampHeight,
                       int stampWidth) {
    const int m = grid.size();
    const int n = grid[0].size();
    // A[i][j] := the number of 1s in grid[0..i)[0..j)
    vector<vector<int>> A(m + 1, vector<int>(n + 1));
    // B[i][j] := the number of ways to stamp the submatrix in [0..i)[0..j)
    vector<vector<int>> B(m + 1, vector<int>(n + 1));
    // fit[i][j] := true if the stamps can fit with the right-bottom at (i, j)
    vector<vector<bool>> fit(m, vector<bool>(n));

    for (int i = 0; i < m; ++i)
      for (int j = 0; j < n; ++j) {
        A[i + 1][j + 1] = A[i + 1][j] + A[i][j + 1] - A[i][j] + grid[i][j];
        if (i + 1 >= stampHeight && j + 1 >= stampWidth) {
          const int x = i - stampHeight + 1;
          const int y = j - stampWidth + 1;
          if (A[i + 1][j + 1] - A[x][j + 1] - A[i + 1][y] + A[x][y] == 0)
            fit[i][j] = true;
        }
      }

    for (int i = 0; i < m; ++i)
      for (int j = 0; j < n; ++j)
        B[i + 1][j + 1] = B[i + 1][j] + B[i][j + 1] - B[i][j] + fit[i][j];

    for (int i = 0; i < m; ++i)
      for (int j = 0; j < n; ++j)
        if (!grid[i][j]) {
          const int x = min(i + stampHeight, m);
          const int y = min(j + stampWidth, n);
          if (B[x][y] - B[i][y] - B[x][j] + B[i][j] == 0)
            return false;
        }

    return true;
  }
};


K Highest Ranked Items Within a Price Range

You are given a 0-indexed 2D integer array `grid` of size `m x n` that
represents a map of the items in a shop. The integers in the grid represent
the following:

* `0` represents a wall that you cannot pass through.
* `1` represents an empty cell that you can freely move to and from.
* All other positive integers represent the price of an item in that cell. You may also freely move to and from these item cells.

It takes `1` step to travel between adjacent grid cells.

You are also given integer arrays `pricing` and `start` where `pricing = [low,
high]` and `start = [row, col]` indicates that you start at the position
`(row, col)` and are interested only in items with a price in the range of
`[low, high]` (inclusive). You are further given an integer `k`.

You are interested in the positions of the `k` highest-ranked items whose
prices are within the given price range. The rank is determined by the first
of these criteria that is different:

1. Distance, defined as the length of the shortest path from the `start` (shorter distance has a higher rank).
2. Price (lower price has a higher rank, but it must be in the price range).
3. The row number (smaller row number has a higher rank).
4. The column number (smaller column number has a higher rank).

Return the `k` highest-ranked items within the price range sorted by their
rank (highest to lowest). If there are fewer than `k` reachable items within
the price range, return all of them.

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 highestRankedKItems(self, grid: List[List[int]], pricing: List[int], start: List[int], k: int) -> List[List[int]]:
    dirs = ((0, 1), (1, 0), (0, -1), (-1, 0))
    m = len(grid)
    n = len(grid[0])
    low, high = pricing
    row, col = start
    ans = []

    if low <= grid[row][col] <= high:
      ans.append([row, col])
      if k == 1:
        return ans

    q = collections.deque([(row, col)])
    seen = {(row, col)}

    while q:
      neighbors = []
      for _ in range(len(q)):
        i, j = q.popleft()
        for t in range(4):
          x = i + dirs[t][0]
          y = j + dirs[t][1]
          if x < 0 or x == m or y < 0 or y == n:
            continue
          if not grid[x][y] or (x, y) in seen:
            continue
          if low <= grid[x][y] <= high:
            neighbors.append([x, y])
          q.append((x, y))
          seen.add((x, y))
      neighbors.sort(key=lambda x: (grid[x[0]][x[1]], x[0], x[1]))
      for neighbor in neighbors:
        if len(ans) < k:
          ans.append(neighbor)
        if len(ans) == k:
          return ans

    return ans

class Solution {
  public List<List<Integer>> highestRankedKItems(int[][] grid, int[] pricing, int[] start, int k) {
    final int[][] DIRS = {{0, 1}, {1, 0}, {0, -1}, {-1, 0}};
    final int m = grid.length;
    final int n = grid[0].length;
    final int low = pricing[0];
    final int high = pricing[1];
    final int row = start[0];
    final int col = start[1];
    List<List<Integer>> ans = new ArrayList<>();

    if (low <= grid[row][col] && grid[row][col] <= high) {
      ans.add(Arrays.asList(row, col));
      if (k == 1)
        return ans;
    }

    Queue<Pair<Integer, Integer>> q = new ArrayDeque<>(List.of(new Pair<>(row, col)));
    boolean[][] seen = new boolean[m][n];
    seen[row][col] = true; // Mark as visited.

    while (!q.isEmpty()) {
      List<List<Integer>> neighbors = new ArrayList<>();
      for (int sz = q.size(); sz > 0; --sz) {
        final int i = q.peek().getKey();
        final int j = q.poll().getValue();
        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 || seen[x][y])
            continue;
          if (low <= grid[x][y] && grid[x][y] <= high)
            neighbors.add(Arrays.asList(x, y));
          q.offer(new Pair<>(x, y));
          seen[x][y] = true;
        }
      }
      Collections.sort(neighbors, new Comparator<List<Integer>>() {
        @Override
        public int compare(List<Integer> a, List<Integer> b) {
          final int x1 = a.get(0);
          final int y1 = a.get(1);
          final int x2 = b.get(0);
          final int y2 = b.get(1);
          if (grid[x1][y1] != grid[x2][y2])
            return grid[x1][y1] - grid[x2][y2];
          return x1 == x2 ? y1 - y2 : x1 - x2;
        }
      });
      for (List<Integer> neighbor : neighbors) {
        if (ans.size() < k)
          ans.add(neighbor);
        if (ans.size() == k)
          return ans;
      }
    }

    return ans;
  }
}

class Solution {
 public:
  vector<vector<int>> highestRankedKItems(vector<vector<int>>& grid,
                                          vector<int>& pricing,
                                          vector<int>& start, int k) {
    constexpr int kDirs[4][2] = {{0, 1}, {1, 0}, {0, -1}, {-1, 0}};
    const int m = grid.size();
    const int n = grid[0].size();
    const int low = pricing[0];
    const int high = pricing[1];
    const int row = start[0];
    const int col = start[1];
    vector<vector<int>> ans;

    if (low <= grid[row][col] && grid[row][col] <= high) {
      ans.push_back({row, col});
      if (k == 1)
        return ans;
    }

    queue<pair<int, int>> q{{{row, col}}};
    vector<vector<bool>> seen(m, vector<bool>(n));
    seen[row][col] = true;  // Mark as visited.

    while (!q.empty()) {
      vector<vector<int>> neighbors;
      for (int sz = q.size(); sz > 0; --sz) {
        const auto [i, j] = q.front();
        q.pop();
        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] || seen[x][y])
            continue;
          if (low <= grid[x][y] && grid[x][y] <= high)
            neighbors.push_back({x, y});
          q.emplace(x, y);
          seen[x][y] = true;
        }
      }
      ranges::sort(neighbors, [&](const vector<int>& a, const vector<int>& b) {
        const int x1 = a[0];
        const int y1 = a[1];
        const int x2 = b[0];
        const int y2 = b[1];
        if (grid[x1][y1] != grid[x2][y2])
          return grid[x1][y1] < grid[x2][y2];
        return x1 == x2 ? y1 < y2 : x1 < x2;
      });
      for (const vector<int>& neighbor : neighbors) {
        if (ans.size() < k)
          ans.push_back(neighbor);
        if (ans.size() == k)
          return ans;
      }
    }

    return ans;
  }
};