Skip to content

Commit 5bae495

Browse files
authored
Create README.md
1 parent f24bcdd commit 5bae495

File tree

1 file changed

+307
-0
lines changed
  • 22 - Backtracking Algorithm Based Problems/02 - N-Queens

1 file changed

+307
-0
lines changed
Lines changed: 307 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,307 @@
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+
![image](https://github.com/user-attachments/assets/e8761c6f-261e-4dcd-b8d3-5ead85274f52)
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

Comments
 (0)