From 9fb39146b7f0fabeca14eec6b0a42ef7abdecaa3 Mon Sep 17 00:00:00 2001 From: YDZ Date: Mon, 31 May 2021 21:21:21 +0800 Subject: [PATCH] Update 0051 solution --- leetcode/0051.N-Queens/51. N-Queens.go | 6 +- leetcode/0051.N-Queens/README.md | 1 + .../ChapterFour/0001~0099/0051.N-Queens.md | 79 ++++++++++--------- 3 files changed, 45 insertions(+), 41 deletions(-) diff --git a/leetcode/0051.N-Queens/51. N-Queens.go b/leetcode/0051.N-Queens/51. N-Queens.go index 040718dd..ba63a910 100644 --- a/leetcode/0051.N-Queens/51. N-Queens.go +++ b/leetcode/0051.N-Queens/51. N-Queens.go @@ -47,7 +47,7 @@ func generateBoard(n int, row *[]int) []string { return board } -// 解法二 二进制操作法 +// 解法二 二进制操作法 Signed-off-by: Hanlin Shi shihanlin9@gmail.com func solveNQueens2(n int) (res [][]string) { placements := make([]string, n) for i := range placements { @@ -61,7 +61,6 @@ func solveNQueens2(n int) (res [][]string) { } placements[i] = string(buf) } - var construct func(prev []int) construct = func(prev []int) { if len(prev) == n { @@ -72,14 +71,12 @@ func solveNQueens2(n int) (res [][]string) { res = append(res, plan) return } - occupied := 0 for i := range prev { dist := len(prev) - i bit := 1 << prev[i] occupied |= bit | bit<>dist } - prev = append(prev, -1) for i := 0; i < n; i++ { if (occupied>>i)&1 != 0 { @@ -89,7 +86,6 @@ func solveNQueens2(n int) (res [][]string) { construct(prev) } } - construct(make([]int, 0, n)) return } diff --git a/leetcode/0051.N-Queens/README.md b/leetcode/0051.N-Queens/README.md index c2be733e..6fcabdee 100755 --- a/leetcode/0051.N-Queens/README.md +++ b/leetcode/0051.N-Queens/README.md @@ -40,4 +40,5 @@ Each solution contains a distinct board configuration of the *n*-queens' placem - 利用 col 数组记录列信息,col 有 `n` 列。用 dia1,dia2 记录从左下到右上的对角线,从左上到右下的对角线的信息,dia1 和 dia2 分别都有 `2*n-1` 个。 - dia1 对角线的规律是 `i + j 是定值`,例如[0,0],为 0;[1,0]、[0,1] 为 1;[2,0]、[1,1]、[0,2] 为 2; - 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 为定值`。 +- 还有一个位运算的方法,每行只能选一个位置放皇后,那么对每行遍历可能放皇后的位置。如何高效判断哪些点不能放皇后呢?这里的做法毕竟巧妙,把所有之前选过的点按照顺序存下来,然后根据之前选的点到当前行的距离,就可以快速判断是不是会有冲突。举个例子: 假如在 4 皇后问题中,如果第一二行已经选择了位置 [1, 3],那么在第三行选择时,首先不能再选 1, 3 列了,而对于第三行, 1 距离长度为2,所以它会影响到 -1, 3 两个列。同理,3 在第二行,距离第三行为 1,所以 3 会影响到列 2, 4。由上面的结果,我们知道 -1, 4 超出边界了不用去管,别的不能选的点是 1, 2, 3,所以第三行就只能选 0。在代码实现中,可以在每次遍历前根据之前选择的情况生成一个 occupied 用来记录当前这一行,已经被选了的和由于之前皇后攻击范围所以不能选的位置,然后只选择合法的位置进入到下一层递归。另外就是预处理了一个皇后放不同位置的字符串,这样这些字符串在返回结果的时候是可以在内存中复用的,省一点内存。 diff --git a/website/content/ChapterFour/0001~0099/0051.N-Queens.md b/website/content/ChapterFour/0001~0099/0051.N-Queens.md index d2d8dbe8..24d976b7 100755 --- a/website/content/ChapterFour/0001~0099/0051.N-Queens.md +++ b/website/content/ChapterFour/0001~0099/0051.N-Queens.md @@ -94,42 +94,49 @@ func generateBoard(n int, row *[]int) []string { return board } -// 解法二 二进制操作法 -// class Solution -// { -// int n; -// string getNq(int p) -// { -// string s(n, '.'); -// s[p] = 'Q'; -// return s; -// } -// void nQueens(int p, int l, int m, int r, vector> &res) -// { -// static vector ans; -// if (p >= n) -// { -// res.push_back(ans); -// return ; -// } -// int mask = l | m | r; -// for (int i = 0, b = 1; i < n; ++ i, b <<= 1) -// if (!(mask & b)) -// { -// ans.push_back(getNq(i)); -// nQueens(p + 1, (l | b) >> 1, m | b, (r | b) << 1, res); -// ans.pop_back(); -// } -// } -// public: -// vector > solveNQueens(int n) -// { -// this->n = n; -// vector> res; -// nQueens(0, 0, 0, 0, res); -// return res; -// } -// }; +// 解法二 二进制操作法 Signed-off-by: Hanlin Shi shihanlin9@gmail.com +func solveNQueens2(n int) (res [][]string) { + placements := make([]string, n) + for i := range placements { + buf := make([]byte, n) + for j := range placements { + if i == j { + buf[j] = 'Q' + } else { + buf[j] = '.' + } + } + placements[i] = string(buf) + } + var construct func(prev []int) + construct = func(prev []int) { + if len(prev) == n { + plan := make([]string, n) + for i := 0; i < n; i++ { + plan[i] = placements[prev[i]] + } + res = append(res, plan) + return + } + occupied := 0 + for i := range prev { + dist := len(prev) - i + bit := 1 << prev[i] + occupied |= bit | bit<>dist + } + prev = append(prev, -1) + for i := 0; i < n; i++ { + if (occupied>>i)&1 != 0 { + continue + } + prev[len(prev)-1] = i + construct(prev) + } + } + construct(make([]int, 0, n)) + return +} + ```