Skip to content

Commit 9fb3914

Browse files
committed
Update 0051 solution
1 parent e256d74 commit 9fb3914

File tree

3 files changed

+45
-41
lines changed

3 files changed

+45
-41
lines changed

leetcode/0051.N-Queens/51. N-Queens.go

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@ func generateBoard(n int, row *[]int) []string {
4747
return board
4848
}
4949

50-
// 解法二 二进制操作法
50+
// 解法二 二进制操作法 Signed-off-by: Hanlin Shi shihanlin9@gmail.com
5151
func solveNQueens2(n int) (res [][]string) {
5252
placements := make([]string, n)
5353
for i := range placements {
@@ -61,7 +61,6 @@ func solveNQueens2(n int) (res [][]string) {
6161
}
6262
placements[i] = string(buf)
6363
}
64-
6564
var construct func(prev []int)
6665
construct = func(prev []int) {
6766
if len(prev) == n {
@@ -72,14 +71,12 @@ func solveNQueens2(n int) (res [][]string) {
7271
res = append(res, plan)
7372
return
7473
}
75-
7674
occupied := 0
7775
for i := range prev {
7876
dist := len(prev) - i
7977
bit := 1 << prev[i]
8078
occupied |= bit | bit<<dist | bit>>dist
8179
}
82-
8380
prev = append(prev, -1)
8481
for i := 0; i < n; i++ {
8582
if (occupied>>i)&1 != 0 {
@@ -89,7 +86,6 @@ func solveNQueens2(n int) (res [][]string) {
8986
construct(prev)
9087
}
9188
}
92-
9389
construct(make([]int, 0, n))
9490
return
9591
}

leetcode/0051.N-Queens/README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,4 +40,5 @@ Each solution contains a distinct board configuration of the *n*-queens' placem
4040
- 利用 col 数组记录列信息,col 有 `n` 列。用 dia1,dia2 记录从左下到右上的对角线,从左上到右下的对角线的信息,dia1 和 dia2 分别都有 `2*n-1` 个。
4141
- dia1 对角线的规律是 `i + j 是定值`,例如[0,0],为 0;[1,0][0,1] 为 1;[2,0][1,1][0,2] 为 2;
4242
- dia2 对角线的规律是 `i - j 是定值`,例如[0,7],为 -7;[0,6][1,7] 为 -6;[0,5][1,6][2,7] 为 -5;为了使他们从 0 开始,i - j + n - 1 偏移到 0 开始,所以 dia2 的规律是 `i - j + n - 1 为定值`
43+
- 还有一个位运算的方法,每行只能选一个位置放皇后,那么对每行遍历可能放皇后的位置。如何高效判断哪些点不能放皇后呢?这里的做法毕竟巧妙,把所有之前选过的点按照顺序存下来,然后根据之前选的点到当前行的距离,就可以快速判断是不是会有冲突。举个例子: 假如在 4 皇后问题中,如果第一二行已经选择了位置 [1, 3],那么在第三行选择时,首先不能再选 1, 3 列了,而对于第三行, 1 距离长度为2,所以它会影响到 -1, 3 两个列。同理,3 在第二行,距离第三行为 1,所以 3 会影响到列 2, 4。由上面的结果,我们知道 -1, 4 超出边界了不用去管,别的不能选的点是 1, 2, 3,所以第三行就只能选 0。在代码实现中,可以在每次遍历前根据之前选择的情况生成一个 occupied 用来记录当前这一行,已经被选了的和由于之前皇后攻击范围所以不能选的位置,然后只选择合法的位置进入到下一层递归。另外就是预处理了一个皇后放不同位置的字符串,这样这些字符串在返回结果的时候是可以在内存中复用的,省一点内存。
4344

website/content/ChapterFour/0001~0099/0051.N-Queens.md

Lines changed: 43 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -94,42 +94,49 @@ func generateBoard(n int, row *[]int) []string {
9494
return board
9595
}
9696

97-
// 解法二 二进制操作法
98-
// class Solution
99-
// {
100-
// int n;
101-
// string getNq(int p)
102-
// {
103-
// string s(n, '.');
104-
// s[p] = 'Q';
105-
// return s;
106-
// }
107-
// void nQueens(int p, int l, int m, int r, vector<vector<string>> &res)
108-
// {
109-
// static vector<string> ans;
110-
// if (p >= n)
111-
// {
112-
// res.push_back(ans);
113-
// return ;
114-
// }
115-
// int mask = l | m | r;
116-
// for (int i = 0, b = 1; i < n; ++ i, b <<= 1)
117-
// if (!(mask & b))
118-
// {
119-
// ans.push_back(getNq(i));
120-
// nQueens(p + 1, (l | b) >> 1, m | b, (r | b) << 1, res);
121-
// ans.pop_back();
122-
// }
123-
// }
124-
// public:
125-
// vector<vector<string> > solveNQueens(int n)
126-
// {
127-
// this->n = n;
128-
// vector<vector<string>> res;
129-
// nQueens(0, 0, 0, 0, res);
130-
// return res;
131-
// }
132-
// };
97+
// 解法二 二进制操作法 Signed-off-by: Hanlin Shi shihanlin9@gmail.com
98+
func solveNQueens2(n int) (res [][]string) {
99+
placements := make([]string, n)
100+
for i := range placements {
101+
buf := make([]byte, n)
102+
for j := range placements {
103+
if i == j {
104+
buf[j] = 'Q'
105+
} else {
106+
buf[j] = '.'
107+
}
108+
}
109+
placements[i] = string(buf)
110+
}
111+
var construct func(prev []int)
112+
construct = func(prev []int) {
113+
if len(prev) == n {
114+
plan := make([]string, n)
115+
for i := 0; i < n; i++ {
116+
plan[i] = placements[prev[i]]
117+
}
118+
res = append(res, plan)
119+
return
120+
}
121+
occupied := 0
122+
for i := range prev {
123+
dist := len(prev) - i
124+
bit := 1 << prev[i]
125+
occupied |= bit | bit<<dist | bit>>dist
126+
}
127+
prev = append(prev, -1)
128+
for i := 0; i < n; i++ {
129+
if (occupied>>i)&1 != 0 {
130+
continue
131+
}
132+
prev[len(prev)-1] = i
133+
construct(prev)
134+
}
135+
}
136+
construct(make([]int, 0, n))
137+
return
138+
}
139+
133140

134141
```
135142

0 commit comments

Comments
 (0)