Skip to content

Commit 195d46d

Browse files
authored
Update README.md
1 parent 4c258f0 commit 195d46d

File tree

1 file changed

+120
-193
lines changed
  • 20 - Hashmap Data Structure Problems/03 - N - Queens

1 file changed

+120
-193
lines changed

20 - Hashmap Data Structure Problems/03 - N - Queens/README.md

Lines changed: 120 additions & 193 deletions
Original file line numberDiff line numberDiff line change
@@ -7,97 +7,51 @@
77
![image](https://github.com/user-attachments/assets/e8761c6f-261e-4dcd-b8d3-5ead85274f52)
88

99
## Problem Explanation
10+
#### **Problem Statement**
11+
The **N-Queens problem** is about placing `N` queens on an `N x N` chessboard such that:
12+
- No two queens threaten each other.
13+
- Queens threaten in the same row, same column, or along both diagonals.
1014

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-
15+
We need to find all valid configurations for placing these queens and return them in a specific format:
16+
- Each solution is represented by a list of strings, where each string represents a row.
17+
- For example, if `N = 4`, one solution looks like:
18+
```
19+
.Q..
20+
...Q
21+
Q...
22+
..Q.
23+
```
5724

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**.
6325

6426

27+
#### **Understanding the Approach**
6528

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.
29+
To solve this problem, we use **backtracking**, a recursive approach that explores all possible placements of queens column by column. Here’s a breakdown:
7030

31+
1. **Constraints**:
32+
- Each column must have exactly one queen.
33+
- A queen's position in the current column must not conflict with queens in the previous columns.
7134

35+
2. **Tracking Validity**:
36+
- To check if placing a queen at `(row, col)` is valid:
37+
- **Row**: Check if any queen already occupies this row.
38+
- **Primary diagonal**: No queen should occupy `(row - col)`.
39+
- **Secondary diagonal**: No queen should occupy `(row + col)`.
7240

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.
41+
These checks are implemented efficiently using hash sets.
7542

43+
3. **Recursive Process**:
44+
- Start placing queens from column `0`.
45+
- For the current column:
46+
- Try placing a queen in every row.
47+
- If valid, mark the row and diagonals as occupied.
48+
- Recursively move to the next column.
49+
- If all queens are placed (base case), add the current configuration to the solution.
50+
- Backtrack by removing the queen and marking the row and diagonals as free.
7651

52+
4. **Output Format**:
53+
- Store solutions as a vector of strings.
7754

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.
10155

10256
## Problem Solution
10357
```cpp
@@ -156,152 +110,125 @@ class Solution {
156110
157111
## Problem Solution Explanation
158112
159-
#### **1. Helper Function: `addSolution`**
113+
#### **Helper Function: `addSolution`**
160114
```cpp
161-
void addSolution(vector<vector<string>>& ans, vector<vector<int>>& board, int n) {
115+
void addSolution(vector<vector<string>>& ans, vector<int>& board, int n){
162116
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);
117+
for(int i = 0; i < n; i++){
118+
string row(n, '.'); // Create a string of size 'n', initialized with '.'
119+
row[board[i]] = 'Q'; // Place a queen at the column index stored in board[i]
120+
temp.push_back(row); // Add this row to the solution
172121
}
173-
ans.push_back(temp);
122+
ans.push_back(temp); // Add this configuration to the final answers
174123
}
175124
```
176-
- Converts the `board` into the required string representation and adds it to the `ans` vector.
125+
- This function converts the internal `board` representation (queen positions per column) into the required string format.
126+
- **Example**: If `board = [1, 3, 0, 2]` for `N = 4`, this means:
127+
- Column `0` → Row `1` has a queen → Row: `.Q..`
128+
- Column `1` → Row `3` has a queen → Row: `...Q`
129+
- Column `2` → Row `0` has a queen → Row: `Q...`
130+
- Column `3` → Row `2` has a queen → Row: `..Q.`
177131

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-
}
189132

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-
}
198133

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`**
134+
#### **Recursive Function: `solve`**
217135
```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);
136+
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){
137+
if(col == n){
138+
addSolution(ans, board, n); // If all columns are processed, store the current board configuration
221139
return;
222140
}
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;
141+
for(int row = 0; row < n; row++){ // Try placing a queen in each row of the current column
142+
int diag1 = row - col; // Primary diagonal value
143+
int diag2 = row + col; // Secondary diagonal value
144+
145+
// Check if placing a queen is valid
146+
if(rows.find(row) == rows.end() && primaryDiag.find(diag1) == primaryDiag.end() && secondaryDiag.find(diag2) == secondaryDiag.end()){
147+
board[col] = row; // Place the queen in the current column
148+
rows.insert(row); // Mark this row as occupied
149+
primaryDiag.insert(diag1); // Mark the primary diagonal as occupied
150+
secondaryDiag.insert(diag2); // Mark the secondary diagonal as occupied
151+
152+
solve(col + 1, ans, board, rows, primaryDiag, secondaryDiag, n); // Recurse to the next column
153+
154+
// Backtrack: Remove the queen and mark the row/diagonals as free
155+
board[col] = -1;
156+
rows.erase(row);
157+
primaryDiag.erase(diag1);
158+
secondaryDiag.erase(diag2);
229159
}
230160
}
231161
}
232162
```
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.
163+
- **Base Case**: When `col == n`, all queens are placed, and the current configuration is stored using `addSolution`.
164+
- **Recursive Case**: For each column, try placing a queen in every row and check if the position is valid.
165+
- **Backtracking**: Ensures that the algorithm explores all possibilities by undoing changes made for a failed path.
166+
237167
238-
#### **4. Main Function**
168+
169+
#### **Main Function: `solveNQueens`**
239170
```cpp
240171
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;
172+
vector<int> board(n, -1); // Tracks queen positions for each column (initially no queens placed)
173+
vector<vector<string>> ans; // Stores all valid solutions
174+
unordered_set<int> rows; // Tracks rows that are already occupied
175+
unordered_set<int> primaryDiag; // Tracks primary diagonals that are occupied
176+
unordered_set<int> secondaryDiag; // Tracks secondary diagonals that are occupied
177+
178+
solve(0, ans, board, rows, primaryDiag, secondaryDiag, n); // Start solving from the first column
179+
return ans; // Return the list of all solutions
245180
}
246181
```
247-
- Initializes the board and calls `solve` starting from column 0.
182+
- Initializes all data structures and starts the recursive backtracking process.
248183

249184

250185

251186
### **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-
```
277187

188+
#### **Example: N = 4**
189+
1. Start from column `0`:
190+
- Place queen in `(0, 0)`. Mark row `0` and diagonals `(0 - 0)` and `(0 + 0)` as occupied.
278191

192+
2. Move to column `1`:
193+
- Row `0` is blocked. Try row `1` → Conflicts diagonally.
194+
- Try row `2` → Valid. Place queen in `(2, 1)`.
279195

280-
### **Step 4: Time and Space Complexity**
196+
3. Move to column `2`:
197+
- Row `0` is blocked. Row `1` conflicts diagonally.
198+
- Try row `3` → Valid. Place queen in `(3, 2)`.
281199

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.
200+
4. Move to column `3`:
201+
- Place queen in `(1, 3)`.
202+
- **Valid Configuration Found**:
203+
```
204+
.Q..
205+
...Q
206+
Q...
207+
..Q.
208+
```
286209
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) \).
294210
295211
212+
### **Step 4: Time and Space Complexity**
296213
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.
214+
#### **Time Complexity**
215+
- There are `N!` permutations for placing queens.
216+
- Validity checks for rows and diagonals take O(1).
217+
- Total time complexity: **O(N!)**
300218
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) \).
219+
#### **Space Complexity**
220+
- Space for:
221+
- `board` array: O(N)
222+
- `rows`, `primaryDiag`, `secondaryDiag` sets: O(N)
223+
- Recursive stack: O(N)
224+
- Total space complexity: **O(N)**
303225
304-
3. **Visualize Solutions**:
305-
- Draw the chessboard for smaller \( n \) values to understand how the queens are placed.
306226
307227
228+
### **Step 5: Recommendations for Students**
229+
1. **Visualize the Problem**: Draw the chessboard and manually place queens to understand constraints.
230+
2. **Practice Similar Problems**: Try variations like "Sudoku Solver" and "Knight's Tour."
231+
3. **Understand Diagonal Indexing**:
232+
- `Primary Diagonal`: `row - col`
233+
- `Secondary Diagonal`: `row + col`
234+
4. **Optimize with Bitmasking**: For larger `N`, bitmasking can reduce space usage for row and diagonal tracking.

0 commit comments

Comments
 (0)