|
| 1 | +<h1 align='center'>N - Queens</h1> |
| 2 | + |
| 3 | +## Problem Statement |
| 4 | + |
| 5 | +**Problem URL :** [N-Queens](https://leetcode.com/problems/n-queens/) |
| 6 | + |
| 7 | + |
| 8 | + |
| 9 | +## Problem Explanation |
| 10 | + |
| 11 | +The **N-Queens Problem** is a famous backtracking problem where the goal is to place \(n\) queens on an \(n \times n\) chessboard so that: |
| 12 | +1. No two queens threaten each other. |
| 13 | + - A queen threatens another queen if they are in the same **row**, **column**, or **diagonal**. |
| 14 | +2. You need to find all possible valid arrangements of \(n\) queens and return them in a specific format: |
| 15 | + - Each solution is represented as a list of strings where: |
| 16 | + - A `Q` represents a queen. |
| 17 | + - A `.` represents an empty space. |
| 18 | + |
| 19 | +#### **Example** |
| 20 | +For \(n = 4\), there are two valid solutions: |
| 21 | +```plaintext |
| 22 | +Solution 1: |
| 23 | +[ |
| 24 | + "Q...", |
| 25 | + "...Q", |
| 26 | + ".Q..", |
| 27 | + "..Q." |
| 28 | +] |
| 29 | +
|
| 30 | +Solution 2: |
| 31 | +[ |
| 32 | + "..Q.", |
| 33 | + "Q...", |
| 34 | + "...Q", |
| 35 | + ".Q.." |
| 36 | +] |
| 37 | +``` |
| 38 | + |
| 39 | +#### **Approach** |
| 40 | +To solve this problem, we can use **backtracking**. Backtracking systematically explores all possibilities to build solutions, backtracking (undoing) when a solution violates the constraints. Here's how we can approach this problem step-by-step: |
| 41 | + |
| 42 | + |
| 43 | + |
| 44 | +**1. Represent the Chessboard** |
| 45 | +- Use a **2D array** (`board`) of size \(n \times n\), where: |
| 46 | + - `1` indicates a queen is placed. |
| 47 | + - `0` indicates an empty spot. |
| 48 | +- Initially, the board is filled with `0`. |
| 49 | + |
| 50 | + |
| 51 | + |
| 52 | +**2. Solve Column-by-Column** |
| 53 | +- Start from the **first column** and attempt to place a queen in any valid row. |
| 54 | +- Move to the **next column** only if the queen placement in the current column is valid. |
| 55 | + |
| 56 | + |
| 57 | + |
| 58 | +**3. Safety Check** |
| 59 | +- For every cell `(row, col)` where we attempt to place a queen, we need to ensure: |
| 60 | + 1. **No queen in the same row** to the left of the current column. |
| 61 | + 2. **No queen in the upper-left diagonal**. |
| 62 | + 3. **No queen in the lower-left diagonal**. |
| 63 | + |
| 64 | + |
| 65 | + |
| 66 | +**4. Backtrack if a Solution Fails** |
| 67 | +- If no valid row exists for the current column, backtrack: |
| 68 | + - Remove the last queen placed (reset `board[row][col]` to `0`). |
| 69 | + - Try the next row in the previous column. |
| 70 | + |
| 71 | + |
| 72 | + |
| 73 | +**5. Store Valid Solutions** |
| 74 | +- If queens are successfully placed in all \(n\) columns, convert the `board` to the required string format and save it. |
| 75 | + |
| 76 | + |
| 77 | + |
| 78 | +#### **Example Walkthrough** |
| 79 | +Let’s consider \(n = 4\). |
| 80 | + |
| 81 | +1. **Start with Column 0**: |
| 82 | + - Try placing a queen at `(0, 0)` (row 0, column 0). It's valid. |
| 83 | + - Move to **column 1**. |
| 84 | + |
| 85 | +2. **Column 1**: |
| 86 | + - Try `(0, 1)` → Invalid (same row as `(0, 0)`). |
| 87 | + - Try `(1, 1)` → Valid. Place the queen and move to **column 2**. |
| 88 | + |
| 89 | +3. **Column 2**: |
| 90 | + - Try `(0, 2)` → Invalid (same row as `(0, 0)`). |
| 91 | + - Try `(1, 2)` → Invalid (same row as `(1, 1)`). |
| 92 | + - Try `(2, 2)` → Valid. Place the queen and move to **column 3**. |
| 93 | + |
| 94 | +4. **Column 3**: |
| 95 | + - Try `(0, 3)` → Invalid. |
| 96 | + - Try `(1, 3)` → Invalid. |
| 97 | + - Try `(2, 3)` → Invalid. |
| 98 | + - Try `(3, 3)` → Valid. This completes one solution! |
| 99 | + |
| 100 | +Backtrack and explore other possibilities until all valid solutions are found. |
| 101 | + |
| 102 | +## Problem Solution |
| 103 | +```cpp |
| 104 | +class Solution { |
| 105 | + public: |
| 106 | + |
| 107 | + void addSolution(vector<vector<string>>& ans, vector<int>& board, int n){ |
| 108 | + vector<string> temp; |
| 109 | + |
| 110 | + for(int i = 0; i < n; i++){ |
| 111 | + string row(n, '.'); |
| 112 | + row[board[i]] = 'Q'; |
| 113 | + temp.push_back(row); |
| 114 | + } |
| 115 | + ans.push_back(temp); |
| 116 | + } |
| 117 | + |
| 118 | + void solve(int col, vector<vector<string>>& ans, vector<int>& board, unordered_set<int>& rows, unordered_set<int>& primaryDiag, unordered_set<int>& secondaryDiag, int n){ |
| 119 | + if(col == n){ |
| 120 | + addSolution(ans, board, n); |
| 121 | + return; |
| 122 | + } |
| 123 | + |
| 124 | + for(int row = 0; row < n; row++){ |
| 125 | + int diag1 = row - col; |
| 126 | + int diag2 = row + col; |
| 127 | + |
| 128 | + if(rows.find(row) == rows.end() && primaryDiag.find(diag1) == primaryDiag.end() && secondaryDiag.find(diag2) == secondaryDiag.end()){ |
| 129 | + board[col] = row; |
| 130 | + rows.insert(row); |
| 131 | + primaryDiag.insert(diag1); |
| 132 | + secondaryDiag.insert(diag2); |
| 133 | + |
| 134 | + solve(col + 1, ans, board, rows, primaryDiag, secondaryDiag, n); |
| 135 | + |
| 136 | + board[col] = -1; |
| 137 | + rows.erase(row); |
| 138 | + primaryDiag.erase(diag1); |
| 139 | + secondaryDiag.erase(diag2); |
| 140 | + } |
| 141 | + } |
| 142 | + } |
| 143 | + vector<vector<string>> solveNQueens(int n) { |
| 144 | + vector<int> board(n, -1); |
| 145 | + vector<vector<string>> ans; |
| 146 | + unordered_set<int> rows; |
| 147 | + unordered_set<int> primaryDaig; |
| 148 | + unordered_set<int> secondaryDaig; |
| 149 | + |
| 150 | + solve(0, ans, board, rows, primaryDaig, secondaryDaig, n); |
| 151 | + return ans; |
| 152 | + } |
| 153 | +}; |
| 154 | + |
| 155 | +``` |
| 156 | +
|
| 157 | +## Problem Solution Explanation |
| 158 | +
|
| 159 | +#### **1. Helper Function: `addSolution`** |
| 160 | +```cpp |
| 161 | +void addSolution(vector<vector<string>>& ans, vector<vector<int>>& board, int n) { |
| 162 | + vector<string> temp; |
| 163 | + for (int i = 0; i < n; i++) { |
| 164 | + string row = ""; |
| 165 | + for (int j = 0; j < n; j++) { |
| 166 | + if (board[i][j] == 1) |
| 167 | + row += "Q"; |
| 168 | + else |
| 169 | + row += "."; |
| 170 | + } |
| 171 | + temp.push_back(row); |
| 172 | + } |
| 173 | + ans.push_back(temp); |
| 174 | +} |
| 175 | +``` |
| 176 | +- Converts the `board` into the required string representation and adds it to the `ans` vector. |
| 177 | + |
| 178 | +#### **2. Helper Function: `isSafe`** |
| 179 | +```cpp |
| 180 | +bool isSafe(int row, int col, vector<vector<int>>& board, int n) { |
| 181 | + int x = row; |
| 182 | + int y = col; |
| 183 | + |
| 184 | + // Check left side of the row |
| 185 | + while (y >= 0) { |
| 186 | + if (board[x][y] == 1) return false; |
| 187 | + y--; |
| 188 | + } |
| 189 | + |
| 190 | + // Check upper-left diagonal |
| 191 | + x = row; |
| 192 | + y = col; |
| 193 | + while (x >= 0 && y >= 0) { |
| 194 | + if (board[x][y] == 1) return false; |
| 195 | + x--; |
| 196 | + y--; |
| 197 | + } |
| 198 | + |
| 199 | + // Check lower-left diagonal |
| 200 | + x = row; |
| 201 | + y = col; |
| 202 | + while (x < n && y >= 0) { |
| 203 | + if (board[x][y] == 1) return false; |
| 204 | + x++; |
| 205 | + y--; |
| 206 | + } |
| 207 | + |
| 208 | + return true; |
| 209 | +} |
| 210 | +``` |
| 211 | +- Validates whether a queen can be safely placed at `(row, col)`: |
| 212 | + 1. Checks all positions in the **left row**. |
| 213 | + 2. Checks all positions in the **upper-left diagonal**. |
| 214 | + 3. Checks all positions in the **lower-left diagonal**. |
| 215 | +
|
| 216 | +#### **3. Recursive Function: `solve`** |
| 217 | +```cpp |
| 218 | +void solve(int col, vector<vector<string>>& ans, vector<vector<int>>& board, int n) { |
| 219 | + if (col == n) { |
| 220 | + addSolution(ans, board, n); |
| 221 | + return; |
| 222 | + } |
| 223 | +
|
| 224 | + for (int row = 0; row < n; row++) { |
| 225 | + if (isSafe(row, col, board, n)) { |
| 226 | + board[row][col] = 1; |
| 227 | + solve(col + 1, ans, board, n); |
| 228 | + board[row][col] = 0; |
| 229 | + } |
| 230 | + } |
| 231 | +} |
| 232 | +``` |
| 233 | +- If \( \text{col} = n \), all queens are placed, so call `addSolution`. |
| 234 | +- For each row in the current column: |
| 235 | + 1. Check if it's safe to place a queen. |
| 236 | + 2. If valid, place the queen, move to the next column, and backtrack if needed. |
| 237 | + |
| 238 | +#### **4. Main Function** |
| 239 | +```cpp |
| 240 | +vector<vector<string>> solveNQueens(int n) { |
| 241 | + vector<vector<int>> board(n, vector<int>(n, 0)); |
| 242 | + vector<vector<string>> ans; |
| 243 | + solve(0, ans, board, n); |
| 244 | + return ans; |
| 245 | +} |
| 246 | +``` |
| 247 | +- Initializes the board and calls `solve` starting from column 0. |
| 248 | +
|
| 249 | +
|
| 250 | +
|
| 251 | +### **Step 3: Example Walkthrough** |
| 252 | +Input: \( n = 4 \) |
| 253 | +
|
| 254 | +1. The algorithm explores all possibilities, starting with: |
| 255 | + ``` |
| 256 | + Q... |
| 257 | + ...Q |
| 258 | + .Q.. |
| 259 | + ..Q. |
| 260 | + ``` |
| 261 | +
|
| 262 | +2. After finding a solution, it backtracks to explore: |
| 263 | + ``` |
| 264 | + ..Q. |
| 265 | + Q... |
| 266 | + ...Q |
| 267 | + .Q.. |
| 268 | + ``` |
| 269 | +
|
| 270 | +Output: |
| 271 | +```cpp |
| 272 | +[ |
| 273 | + ["Q...", "...Q", ".Q..", "..Q."], |
| 274 | + ["..Q.", "Q...", "...Q", ".Q.."] |
| 275 | +] |
| 276 | +``` |
| 277 | + |
| 278 | + |
| 279 | + |
| 280 | +### **Step 4: Time and Space Complexity** |
| 281 | + |
| 282 | +#### **Time Complexity** |
| 283 | +- **Backtracking** explores all possible queen placements: |
| 284 | + - The total number of recursive calls is roughly \( O(n!) \) since we attempt to place queens column by column. |
| 285 | +- Checking safety involves \( O(n) \) operations for each queen. |
| 286 | + |
| 287 | +Overall time complexity: \( O(n! \times n) \). |
| 288 | + |
| 289 | +#### **Space Complexity** |
| 290 | +- The `board` requires \( O(n^2) \) space. |
| 291 | +- The recursion stack can grow to \( O(n) \). |
| 292 | + |
| 293 | +Total space complexity: \( O(n^2) \). |
| 294 | + |
| 295 | + |
| 296 | + |
| 297 | +### **Step 5: Recommendations** |
| 298 | +1. **Practice Backtracking**: |
| 299 | + - Try simpler problems like generating all subsets or permutations to strengthen your recursion and backtracking skills. |
| 300 | + |
| 301 | +2. **Optimize Safety Check**: |
| 302 | + - Instead of rechecking the board for threats, consider using hash sets for rows and diagonals to reduce the safety check to \( O(1) \). |
| 303 | + |
| 304 | +3. **Visualize Solutions**: |
| 305 | + - Draw the chessboard for smaller \( n \) values to understand how the queens are placed. |
| 306 | + |
| 307 | + |
0 commit comments