【题解】LeetCode 51. N皇后 / 52. N皇后 II

总结

用的是标准算法,51题超过了98.5%,52题执行时间为0.

解法说明还是在注释中。

  1. golang 没有引用,很多地方都会用到指针。之前我在 C++ 中有意识不用指针,到这里不应该有这个习惯。
  2. 切片本身也是值,形参 append 不会改变实参的 len,可以传递指针。但确实会改变底层的值。
  3. 将一个仍会被使用的切片 append 到别的数据结构是很危险的,它的值会被改变。可以使用 copy 函数。
  4. 字符串相关操作有些麻烦,如创建一个长度为 n,全部是点号的字符串在 C++中只需要 string(n, '.'),而在 golang 中需要先创建 byte 数组,append 完成后再转换成 string.
  5. 字符串不能直接修改,还是需要先转换成 byte 数组.
  6. 也许有相关的库,可以多学习一下。
  7. 围观了更快的人的代码,它将 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
}
发布了375 篇原创文章 · 获赞 305 · 访问量 7万+

猜你喜欢

转载自blog.csdn.net/m0_37809890/article/details/104348453
今日推荐