N-Queens hard
Problem Statement
The n-queens puzzle is the problem of placing n chess queens on an n×n chessboard such that no two queens attack each other.
A queen attacks any piece in the same row, column, or diagonal.
Given an integer n, return all distinct solutions to the n-queens puzzle. Each solution contains a distinct board configuration of the n-queens' placement, where 'Q' and '.' both indicate a queen and an empty space, respectively.
Example 1
Input: n = 4 Output: [[".Q..","...Q","Q...","..Q."],["..Q.","Q...","...Q",".Q.."]] Explanation: There exist two distinct solutions to the 4-queens puzzle as shown above.
Example 2
Input: n = 1 Output: [["Q"]]
Steps
- Backtracking: We'll use a backtracking algorithm to explore all possible placements of queens.
- Board Representation: We'll represent the chessboard using a list of strings (or a 2D array).
- IsSafe Function: A crucial function to check if it's safe to place a queen at a given row and column. This involves checking the row, column, and both diagonals.
- Recursive Function: A recursive function will explore placing queens row by row. If a placement is safe, it recursively calls itself for the next row. If a solution is found (all queens placed), it's added to the result. If no safe placement is found in a row, it backtracks.
Explanation
The backtracking algorithm systematically explores all possible queen placements. The IsSafe
function efficiently determines if a placement is valid by checking for conflicts in the row, column, and diagonals. The recursion ensures that all possible combinations are explored. When a complete solution is found, it's added to the result list. If a queen placement leads to a conflict, the algorithm backtracks to try alternative placements.
Code
using System;
using System.Collections.Generic;
using System.Linq;
public class Solution {
public IList<IList<string>> SolveNQueens(int n) {
IList<IList<string>> result = new List<IList<string>>();
List<string> board = new List<string>();
for (int i = 0; i < n; i++) {
board.Add(new string('.', n));
}
SolveNQueensHelper(result, board, 0);
return result;
}
private void SolveNQueensHelper(IList<IList<string>> result, List<string> board, int row) {
int n = board.Count;
if (row == n) {
result.Add(new List<string>(board)); //Add a copy to avoid modification
return;
}
for (int col = 0; col < n; col++) {
if (IsSafe(board, row, col)) {
board[row] = board[row].Substring(0, col) + 'Q' + board[row].Substring(col + 1);
SolveNQueensHelper(result, board, row + 1);
board[row] = board[row].Substring(0, col) + '.' + board[row].Substring(col + 1); //Backtrack
}
}
}
private bool IsSafe(List<string> board, int row, int col) {
int n = board.Count;
// Check column
for (int i = 0; i < row; i++) {
if (board[i][col] == 'Q') return false;
}
// Check diagonals
for (int i = row - 1, j = col - 1; i >= 0 && j >= 0; i--, j--) {
if (board[i][j] == 'Q') return false;
}
for (int i = row - 1, j = col + 1; i >= 0 && j < n; i--, j++) {
if (board[i][j] == 'Q') return false;
}
return true;
}
}
Complexity
- Time Complexity: O(N!), where N is the size of the board. In the worst case, we explore all possible permutations of queen placements.
- Space Complexity: O(N^2) to store the board and the recursion stack. The space used by the recursion stack is proportional to N in the average case but can be O(N^2) in the worst case if the algorithm goes very deep.