今天来补充下两个困难题
n皇后 n queens
注意, 3*3的本来就是无解的, 可以发现宽度就是for循环, 高度/深度就是回溯
- 终止条件就是到最后一行, row == n
- 单层递归需要判断是否合法, 合法就填Q, 回溯就变成'.'
小知识:
小知识, 单引号是字符, 双引号是字符串; 还有copyValueOf方法的使用
class Solution {
List<List<String>> res = new ArrayList<>();
public List<List<String>> solveNQueens(int n) {
//先要初始化二维数据,填满. 和之前的user数组同理
char[][] chessboard = new char[n][n];
//这里填充要用个for
for(char[] c : chessboard){
Arrays.fill(c, '.');
}
backtracking(n, 0, chessboard);
return res;
}
//n是棋盘的大小, row是用来记录遍历到第几层
public void backtracking(int n, int row, char[][] chessboard){
//终止条件就是遍历完棋盘格
if(row == n){
res.add(Array2List(chessboard));
return;
}
for(int col = 0; col < n; col++){
if(isValid(row, col, n, chessboard)){
chessboard[row][col] = 'Q';
backtracking(n, row+1, chessboard);
//复原成i
chessboard[row][col] = '.';
}
}
}
public boolean isValid(int row, int col, int n, char[][] chessboard){
//检查列
for(int i = 0; i < row; i++){
if(chessboard[i][col] == 'Q'){
return false;
}
}
//检查45度角, 也就是棋盘的右上角, 看清楚条件
for(int i = row - 1, j = col + 1; i >= 0 && j <= n - 1; i--, j++){
if(chessboard[i][j] == 'Q'){
return false;
}
}
//检查135度角, 也就是右下角
for(int i = row - 1, j = col - 1; i >= 0 && j >= 0; i--, j--){
if(chessboard[i][j] == 'Q'){
return false;
}
}
//注意:不需要对行进行判断, 因为已经包括了
return true;
}
//还需要一个方法, 因为chessboard是char二维数组, 但是最后是集合
public List Array2List(char[][] chessboard){
//里面要创建一个list收集元素, 最后在回溯里才让
List<String> list = new ArrayList<>();
for(char[] n : chessboard){
list.add(String.copyValueOf(n));
}
return list;
}
}
解数独
二维递归是关键点
同时也不需要终止条件, 因为填满了就会自己结束
解数独找到一个符合的条件(就在树的叶子节点上)立刻就返回,相当于找从根节点到叶子节点一条唯一路径,所以需要使用bool返回值
(注意: 这不是最优解, 时间复杂度非常高)
class Solution {
public void solveSudoku(char[][] board) {
backtracking(board);
}
public boolean backtracking(char[][] board){
//一个遍历行, 一个遍历列
//一行一列确认后, 递归遍历这个位置放九个数字的可能性
for(int i = 0; i < 9; i++){
for(int j = 0; j < 9; j++){
//跳过已有的数字
if(board[i][j] != '.'){
continue;
}
for(char k = '1'; k <= '9'; k++){
if(isValid(i,j,k,board)){
board[i][j] = k;
if(backtracking(board)){
return true;
}
board[i][j] = '.';
}
}
return false;
}
}
return true;
}
public boolean isValid(int row, int col, char val, char[][] board){
//同行是否重复
for(int i = 0; i < 9; i++){
if(board[row][i] == val){
return false;
}
}
//列
for(int j = 0; j < 9; j++){
if(board[j][col] == val){
return false;
}
}
//九宫格里是否重复
int startRow = (row / 3)*3;
int startCol = (col / 3)*3;
for(int i = startRow; i < startRow + 3; i++){
for(int j = startCol; j < startCol + 3; j++){
if(board[i][j] == val){
return false;
}
}
}
return true;
}
}