Two unrelated advanced tools bundled for the day: one about smarter shortest-path search, one about edge-covering tours.
A* orders its frontier by f(n) = g(n) + h(n), where g is the known cost from start and h is the estimated cost to goal. When h ≡ 0, A* degenerates to Dijkstra.
Common admissible heuristics: Manhattan distance (4-dir grids), Euclidean (free movement), Chebyshev (8-dir).
Hierholzer's algorithm builds the tour in O(E): walk edges greedily, and whenever you get stuck, splice in sub-tours. Implemented with a stack, appending to the route in post-order and reversing at the end.
A* on a grid (Manhattan heuristic), then Hierholzer for an Eulerian path.
import java.util.*;
/** A* on a grid. h = Manhattan distance to goal (admissible for 4-dir). */
public int aStar(int[][] grid, int[] start, int[] goal) {
int R = grid.length, C = grid[0].length;
int[][] dirs = {{1,0},{-1,0},{0,1},{0,-1}};
int[][] g = new int[R][C];
for (int[] row : g) Arrays.fill(row, Integer.MAX_VALUE);
g[start[0]][start[1]] = 0;
// frontier: {f, r, c}, ordered by f = g + h
PriorityQueue<int[]> pq = new PriorityQueue<>((a,b) -> a[0] - b[0]);
pq.offer(new int[]{h(start, goal), start[0], start[1]});
while (!pq.isEmpty()) {
int[] cur = pq.poll();
int r = cur[1], c = cur[2];
if (r == goal[0] && c == goal[1]) return g[r][c];
for (int[] d : dirs) {
int nr = r + d[0], nc = c + d[1];
if (nr<0||nr>=R||nc<0||nc>=C||grid[nr][nc]==1) continue;
if (g[r][c] + 1 < g[nr][nc]) {
g[nr][nc] = g[r][c] + 1;
int f = g[nr][nc] + h(new int[]{nr,nc}, goal);
pq.offer(new int[]{f, nr, nc});
}
}
}
return -1;
}
private int h(int[] a, int[] b) { // Manhattan — admissible
return Math.abs(a[0]-b[0]) + Math.abs(a[1]-b[1]);
}
/** Hierholzer's Eulerian path (directed). Assumes existence conditions hold. */
public List<Integer> eulerian(int start, List<Deque<Integer>> adj) {
Deque<Integer> stack = new ArrayDeque<>();
LinkedList<Integer> route = new LinkedList<>();
stack.push(start);
while (!stack.isEmpty()) {
int u = stack.peek();
if (!adj.get(u).isEmpty()) stack.push(adj.get(u).poll()); // follow an edge
else route.addFirst(stack.pop()); // stuck ⇒ backtrack, prepend
}
return route; // edges each used exactly once
}
| Disguise / phrasing | What's really asked | Twist to handle |
|---|---|---|
| "Shortest path on a large grid with a goal" | A* (or BFS/Dijkstra) | Add admissible heuristic to prune; interviews often accept plain BFS |
| "8-puzzle / sliding puzzle min moves" | A* on state space | Heuristic = misplaced tiles / sum of Manhattan |
| "Reconstruct itinerary / use all tickets" | Eulerian path | Hierholzer; lexical order → sort adjacency |
| "Valid arrangement of pairs / dominoes" | Eulerian path on a pair graph | Nodes = values, edges = pairs |
| "Can you draw this in one stroke?" | Eulerian existence | Check odd-degree count (0 or 2) |
| "Cracking all codes / de Bruijn sequence" | Eulerian circuit on de Bruijn graph | Overlap edges; Hierholzer |