文章目录
- [一. 力扣 [51. N 皇后](https://leetcode.cn/problems/n-queens/description/)](#一. 力扣 51. N 皇后)
-
- [1. 题目解析](#1. 题目解析)
- [2. 算法原理](#2. 算法原理)
- [3. 代码](#3. 代码)
- [二. 力扣 [526. 优美的排列](https://leetcode.cn/problems/beautiful-arrangement/description/)](#二. 力扣 526. 优美的排列)
-
- [1. 题目解析](#1. 题目解析)
- [2. 算法原理](#2. 算法原理)
- [3. 代码](#3. 代码)
- [三. 力扣 [36. 有效的数独](https://leetcode.cn/problems/valid-sudoku/description/)](#三. 力扣 36. 有效的数独)
-
- [1. 题目解析](#1. 题目解析)
- [2. 算法原理](#2. 算法原理)
- [3. 代码](#3. 代码)
- [四. 力扣 [37. 解数独](https://leetcode.cn/problems/sudoku-solver/description/)](#四. 力扣 37. 解数独)
-
- [1. 题目解析](#1. 题目解析)
- [2. 算法原理](#2. 算法原理)
- [3. 代码](#3. 代码)
一. 力扣 51. N 皇后
1. 题目解析
题目的主要要求是皇后不能处在同行同列以及对角线上, 同时输出结果是二维数组, 每一行的元素需要包含方案的所有坐标

2. 算法原理
决策树
原理
3. 代码
java
class Solution {
List<List<String>> ret;
List<String> path;
boolean[] col;
boolean[] dig1;
boolean[] dig2;
public List<List<String>> solveNQueens(int n) {
ret = new ArrayList<>();
path = new ArrayList<>();
col = new boolean[n];
dig1 = new boolean[2 * n];
dig2 = new boolean[2 * n];
dfs(n, 0);
return ret;
}
void dfs(int n, int r) {
if (r == n) {
ret.add(new ArrayList(path));
return;
}
// i代表列, 即纵坐标, r为横坐标
for (int i = 0; i < n; i++) {
// 剪枝掉不满足的情况
if (!col[i] && !dig1[r - i + n] && !dig2[r + i]) {
col[i] = dig1[r - i + n] = dig2[r + i] = true;
// 将结果添加到path中
StringBuilder tmp = new StringBuilder();
for (int j = 0; j < n; j++) {
if (j == i) {
tmp.append("Q");
}else {
tmp.append(".");
}
}
path.add(tmp.toString());
// 向下一层遍历
dfs(n, r + 1);
// 回溯
path.remove(path.size() - 1);
col[i] = dig1[r - i + n] = dig2[r + i] = false;
}
}
}
}
二. 力扣 526. 优美的排列
1. 题目解析
2. 算法原理
3. 代码
java
class Solution {
int ret = 0;
boolean[] check;
public int countArrangement(int n) {
check = new boolean[n + 1];
dfs(n, 1);
return ret;
}
void dfs(int n, int pos) {
if (pos == n + 1) {
ret++;
return;
}
for (int i = 1; i <= n; i++) {
if (!check[i] && (i % pos == 0 || pos % i == 0)) {
check[i] = true;
dfs(n, pos + 1);
// 回溯
check[i] = false;
}
}
}
}
三. 力扣 36. 有效的数独
1. 题目解析
这里和N皇后有点类似, 但不同的是对角线可以相同
2. 算法原理
3. 代码
java
class Solution {
public boolean isValidSudoku(char[][] board) {
boolean[][] row = new boolean[9][10];
boolean[][] col = new boolean[9][10];
boolean[][][] grid = new boolean[3][3][10];
for (int i = 0; i < 9; i++) {
for (int j = 0; j < 9; j++) {
if (board[i][j] == '.') {
continue;
}
int k = board[i][j] - '0';
if (board[i][j] >= '1' && board[i][j] <= '9' && !row[i][k] && !col[j][k] && !grid[i / 3][j / 3][k]) {
row[i][k] = true;
col[j][k] = true;
grid[i / 3][j / 3][k] = true;
}else {
return false;
}
}
}
return true;
}
}
四. 力扣 37. 解数独
1. 题目解析
与上道题基本一致, 但这里是填写数字
2. 算法原理
与N皇后十分类似, 但是因为我们可能存在填错的情况, 因此每次递归都要两层循环来遍历二维数组, 同时要有第三层循环来试1-9这九个数字, dfs是有返回值的, 重点中的重点是理解什么时候返回false, 什么时候返回true
3. 代码
java
class Solution {
boolean[][] row = new boolean[9][10];
boolean[][] col = new boolean[9][10];
boolean[][][] grid = new boolean[3][3][10];
public void solveSudoku(char[][] board) {
for (int i = 0; i < 9; i++) {
for (int j = 0; j < 9; j++) {
if (board[i][j] != '.') {
int k = board[i][j] - '0';
row[i][k] = true;
col[j][k] = true;
grid[i / 3][j / 3][k] = true;
}
}
}
dfs(board);
}
boolean dfs(char[][] board) {
for (int i = 0; i < 9; i++) {
for (int j = 0; j < 9; j++) {
if (board[i][j] == '.') {
for (int k = 1; k <= 9; k++) {
if (!row[i][k] && !col[j][k] && !grid[i / 3][j / 3][k]) {
row[i][k] = true;
col[j][k] = true;
grid[i / 3][j / 3][k] = true;
board[i][j] = (char)(k + 48);
// 这里我们做判断, 当前情况正确时, 我们直接返回给上一层, 也有保留填写好board的作用
if (dfs(board)) {
return true;
}
// 当前情况不满足, 继续试其他数字, 恢复现场
row[i][k] = false;
col[j][k] = false;
grid[i / 3][j / 3][k] = false;
board[i][j] = '.';
}
}
// 有空格但没有填写数字, 说明情况不成立, 再次剪枝, 不用继续枚举错误情况
return false;
}
}
}
// 全部填满
return true;
}
}







