总结
用的是标准算法,51题超过了98.5%,52题执行时间为0.
解法说明还是在注释中。
- golang 没有引用,很多地方都会用到指针。之前我在 C++ 中有意识不用指针,到这里不应该有这个习惯。
- 切片本身也是值,形参 append 不会改变实参的 len,可以传递指针。但确实会改变底层的值。
- 将一个仍会被使用的切片 append 到别的数据结构是很危险的,它的值会被改变。可以使用 copy 函数。
- 字符串相关操作有些麻烦,如创建一个长度为 n,全部是点号的字符串在 C++中只需要
string(n, '.')
,而在 golang 中需要先创建 byte 数组,append 完成后再转换成 string. - 字符串不能直接修改,还是需要先转换成 byte 数组.
- 也许有相关的库,可以多学习一下。
- 围观了更快的人的代码,它将 dfs 函数直接定义在了函数中,使用函数中之前定义的变量作为 dfs 的状态,省略了参数传递的时间,很漂亮。
leetcode 的数据都很小,为了方便起见我的占用数组只开了20也能通过,说明题目中可能没有大于10的数据.
检查器部分
package main
import "fmt"
type TestCase struct {
n int
output [][]string
}
var cases = []TestCase{{
4, [][]string{
[]string {
".Q..",
"...Q",
"Q...",
"..Q.",
},
[]string {
"..Q.",
"Q...",
"...Q",
".Q..",
},
},
}}
func main() {
for _, kase := range cases {
if res := solveNQueens(kase.n); !testEqual(res, kase.output) {
fmt.Println("failed in:", kase, " your res =", res)
break
} else {
fmt.Println("case", kase, "check success.")
}
}
}
func testEqual(slice1, slice2 [][]string) bool {
if len(slice1) != len(slice2) {
return false
}
for i := range slice1 {
if len(slice1[i]) != len(slice2[i]) {
return false
}
for j := range slice1[i] {
if slice1[i][j] != slice2[i][j] {
return false
}
}
}
return true
}
51题代码
// n 皇后问题研究的是如何将 n 个皇后放置在 n×n 的棋盘上,并且使皇后彼此之间不能相互攻击。
// 给定一个整数 n,返回所有不同的 n 皇后问题的解决方案。
// 每一种解法包含一个明确的 n 皇后问题的棋子放置方案,该方案中 'Q' 和 '.' 分别代表了皇后和空位。
// n 皇后问题的实质是找到一个排列 p,使得对于任意 0<=i<j<n, 满足 i+p[i]!=j+p[j], i-p[i]!=j-p[j]
// 整体框架是首先搜索出所有的排列,然后再构造棋盘方案
// dfs 找到所有可行的排列,每找到一个方案就将其添加在 plan 中
// n 表示棋盘大小, row 表示当前正在填的行数(从 0 开始)
// now 即为当前的排列,每次递归到第 n 层时需要将其添加在 plan 尾部
// occupy 是一个 3 行的切片,分别表示列、副对角线、主对角线的占用情况
// 举例来说,要填 row 行的 col 列时,需要满足 occupy[0][col], occupy[1][row+col], occupy[2][row-col+n] 均是 false
// 并且在填充完毕后将它们置为 true
func dfs(n, row int, now []int, occupy [][20]bool, plan *[][]int) {
if row==n {
tmp := make([]int, n)
copy(tmp, now)
*plan = append(*plan, tmp)
return
}
for col:=0; col<n; col++ {
if !occupy[0][col] && !occupy[1][row+col] && !occupy[2][row-col+n] {
occupy[0][col], occupy[1][row+col], occupy[2][row-col+n] = true, true, true
now[row] = col
dfs(n, row+1, now, occupy, plan)
occupy[0][col], occupy[1][row+col], occupy[2][row-col+n] = false, false, false
}
}
}
// 通过排列构造棋盘
func build_answer(n int, plan [][]int) [][]string {
var res [][]string
for _, plan_0 := range plan {
var res_0 []string
for i:=0; i<n; i++ {
var t []byte
for j:=0; j<n; j++ {
t = append(t, '.')
}
t[plan_0[i]] = 'Q'
res_0 = append(res_0, string(t))
}
res = append(res, res_0)
}
return res
}
func solveNQueens(n int) [][]string {
var plan [][]int
dfs(n, 0, make([]int, n), make([][20]bool, 3), &plan)
answer := build_answer(n, plan)
return answer
}
52题代码
func dfs(n, row int, occupy [][20]bool, answer *int) {
if row==n {
*answer++
return
}
for col:=0; col<n; col++ {
if !occupy[0][col] && !occupy[1][row+col] && !occupy[2][row-col+n] {
occupy[0][col], occupy[1][row+col], occupy[2][row-col+n] = true, true, true
dfs(n, row+1, occupy, answer)
occupy[0][col], occupy[1][row+col], occupy[2][row-col+n] = false, false, false
}
}
}
func totalNQueens(n int) int {
res := 0
dfs(n, 0, make([][20]bool, 3), &res)
return res
}