Lesson 31 of 70 5 min

MANG Problem #12: N-Queens (Hard)

Master the backtracking pattern to place N queens on an NxN board without any queen attacking another.

Reading Mode

Hide the curriculum rail and keep the lesson centered for focused reading.

1. Problem Statement

Mental Model

Breaking down a complex problem into its most efficient algorithmic primitive.

The n-queens puzzle is the problem of placing n queens on an n x n chessboard such that no two queens attack each other.

Return all distinct solutions to the n-queens puzzle.

2. Approach: Row-by-Row Backtracking

graph TD
    subgraph "Diagonal Constraints"
        Pos[Positive Diagonal: r + c = Constant]
        Neg[Negative Diagonal: r - c = Constant]
    end
    
    Backtrack[Row r] --> Loop[Try Col c]
    Loop --> Check{Safe?}
    Check -- Yes --> Recurse[Row r + 1]
    Check -- No --> NextCol[Try Next c]

We can place exactly one queen per row. The problem then becomes: "For each row, which column is safe?"

  1. State: row index.
  2. Choices: col indices from 0 to $N-1$.
  3. Constraints: A queen at (r, c) is safe if no other queen is in:
    • The same column c.
    • The positive diagonal (r + c).
    • The negative diagonal (r - c).
  4. Backtrack: Place queen, recurse to row + 1, then remove queen.

3. Java Implementation

class Solution {
    private Set<Integer> cols = new HashSet<>();
    private Set<Integer> posDiag = new HashSet<>(); // r + c
    private Set<Integer> negDiag = new HashSet<>(); // r - c
    private List<List<String>> res = new ArrayList<>();

    public List<List<String>> solveNQueens(int n) {
        char[][] board = new char[n][n];
        for (char[] row : board) Arrays.fill(row, '.');
        backtrack(0, n, board);
        return res;
    }

    private void backtrack(int r, int n, char[][] board) {
        if (r == n) {
            res.add(construct(board));
            return;
        }

        for (int c = 0; c < n; c++) {
            if (cols.contains(c) || posDiag.contains(r + c) || negDiag.contains(r - c)) {
                continue;
            }

            // Choose
            cols.add(c); posDiag.add(r + c); negDiag.add(r - c);
            board[r][c] = 'Q';

            // Explore
            backtrack(r + 1, n, board);

            // Un-choose (Backtrack)
            cols.remove(c); posDiag.remove(r + c); negDiag.remove(r - c);
            board[r][c] = '.';
        }
    }
}

4. 5-Minute "Video-Style" Walkthrough

  1. The "Aha!" Moment: How do we check diagonals in $O(1)$?
    • Every cell on a diagonal sloping from top-right to bottom-left has the same sum of row and column (r + c).
    • Every cell on a diagonal sloping from top-left to bottom-right has the same difference of row and column (r - c).
  2. The State Management: We use three HashSets (or boolean arrays) to track blocked paths. This is significantly faster than scanning the board for every placement.
  3. The Symmetry: Note that N-Queens solutions are often symmetric. While we solve for all, you could theoretically optimize by solving for half the board and mirroring.

5. Interview Discussion

  • Interviewer: "What is the time complexity?"
  • You: "It is $O(N!)$ because we have $N$ choices for the first row, $N-2$ for the second, and so on. It is much better than a brute force $O(N^N)$."
  • Interviewer: "How can we optimize the space?"
  • You: "Instead of HashSet<Integer>, we can use Boolean arrays of size $N$ and $2N$ for columns and diagonals. For absolute peak performance, we could use Bitmasks."

5. Verbal Interview Script (Staff Tier)

Interviewer: "Walk me through your optimization strategy for this problem."

You: "When approaching this type of challenge, my primary objective is to identify the underlying Monotonicity or Optimal Substructure that allow us to bypass a naive brute-force search. In my implementation of 'MANG Problem #12: N-Queens (Hard)', I focused on reducing the time complexity by leveraging a HashMap-based lookup. This allows us to handle input sizes that would typically cause a standard O(N^2) approach to fail. Furthermore, I prioritized memory efficiency by using in-place modifications. This ensures that the application remains performant even under heavy garbage collection pressure in a high-concurrency Java environment."

6. Staff-Level Interview Follow-Ups

Once you provide the optimized solution, a senior interviewer at Google or Meta will likely push you further. Here is how to handle the most common follow-ups:

Follow-up 1: "How does this scale to a Distributed System?"

If the input data is too large to fit on a single machine (e.g., billions of records), we would move from a single-node algorithm to a MapReduce or Spark-based approach. We would shard the data based on a consistent hash of the keys and perform local aggregations before a global shuffle and merge phase, similar to the logic used in External Merge Sort.

Follow-up 2: "What are the Concurrency implications?"

In a multi-threaded Java environment, we must ensure that our state (e.g., the DP table or the frequency map) is thread-safe. While we could use synchronized blocks, a higher-performance approach would be to use AtomicVariables or ConcurrentHashMap. For problems involving shared arrays, I would consider a Work-Stealing pattern where each thread processes an independent segment of the data to minimize lock contention.

7. Performance Nuances (The Java Perspective)

  1. Autoboxing Overhead: When using HashMap<Integer, Integer>, Java performs autoboxing which creates thousands of Integer objects on the heap. In a performance-critical system, I would use a primitive-specialized library like fastutil or Trove to use Int2IntMap, significantly reducing GC pauses.
  2. Recursion Depth: As discussed in the code, recursive solutions are elegant but risky for deep inputs. I always ensure the recursion depth is bounded, or I rewrite the logic to be Iterative using an explicit stack on the heap to avoid StackOverflowError.

Key Takeaways

  • The same column c.
  • The positive diagonal (r + c).
  • The negative diagonal (r - c).

Want to track your progress?

Sign in to save your progress, track completed lessons, and pick up where you left off.