代码随想录第三十天|这道题好难
Leetcode 51. N 皇后
题目链接: N 皇后
自己的思路:看着很难的一道题,但其实确实难!
正确思路:难点在于之前处理的都是一维数组,现在转变为了而且数组,这个题难点在于思想上的转变以及对判断当前二维数组是否有效的判断(其实函数也不难);回溯三部曲:1、传入参数:当前棋盘,当前遍历棋盘的行数以及总行数n;2、返回值:当遍历棋盘的行数等于总行数的时候,将数组加入到结果集中;3、单层逻辑:先判断当前棋盘是否有效,如果有效,将当前点赋值为’Q’,然后递归回溯,否则判断下一个棋盘是否有效!!
代码:
class Solution {
List<List<String>> res = new ArrayList<>();
public List<List<String>> solveNQueens(int n) {
char[][] path = new char[n][n];
for (char[] c:path){
Arrays.fill(c,'.');
}
backtracking(path,n,0);
return res;
}
public void backtracking(char[][] bash,int n,int row){
if (row==n){
res.add(charToList(bash));
return;
}
for (int i =0;i<n;i++){
if(isvalid(bash,row,i,n)){
bash[row][i]='Q';
backtracking(bash,n,row+1);
bash[row][i]='.';
}
}
}
//将二维数组转成List
public List<String> charToList(char[][] bash){
List<String> list = new ArrayList<>();
for (char[] c:bash){
list.add(new String(c));
}
return list;
}
//判断当前行当前列是否有效
public boolean isvalid(char[][] bash,int row,int col,int n){
//该列是否有效
for (int i=0;i<row;i++){
if (bash[i][col]=='Q') return false;
}
//45°角是否有效
for (int i=row-1,j=col-1;i>=0&&j>=0;i--,j--){
if (bash[i][j]=='Q') return false;
}
//135°角是否有效
for (int i =row-1,j=col+1;i>=0&&j<n;i--,j++){
if (bash[i][j]=='Q') return false;
}
return true;
}
}
复杂度分析:
时间复杂度:
O
(
n
)
\mathcal{O}(n)
O(n)
空间复杂度:
O
(
1
)
\mathcal{O}(1)
O(1)
Leetcode 37. 解数独
题目链接: 解数独
自己的思路:这道题也是非常难得题,因为我不会!
正确思路:这道题从一维回溯转变为了二维回溯,需要对整个矩阵进行回溯,所以是两个for循环,然后去判断当前元素是否是’.‘,如果是的话继续使用k循环字符’1’到’9’,然后判断当前网格i,j位置放置字符是否合理,如果合理进行递归回溯,这个题回溯和其他的题不一样,先将i和j位置放置k,然后递归,返回一个布尔值,这个题为什么使用布尔值当做返回函数呢,因为这个题只需要一个数独矩阵就可以,因为题目只要求返回一个,所以在for循环之前的返回条件直接去掉,在递归之后加入返回条件,如果递归的返回值为真,则向上返回真,如果不是的话就将i,j位置再重新赋值为’.‘,那么第一次出现的true或者false是从哪来的呢,当遍历完’1’到’9’之后,发现没有任何一个有效的,直接返回false,那么true又是哪来的呢,当遍历完两个for循环之后,返回true,那么为什么没有走false,但是却走到了true呢,因为如果遍历完整个棋盘以后,棋盘上就没有是’.'的位置了,就不会走if了,直接返回了true!!
代码:
class Solution {
public void solveSudoku(char[][] board) {
backtracking(board);
}
//返回值为布尔类型
public boolean backtracking(char[][] board){
for (int i=0;i<board.length;i++){
for (int j=0;j<board[0].length;j++){
if (board[i][j]=='.'){
for (char k='1';k<='9';k++){
if (isvalid(i,j,k,board)){
board[i][j]=k;
boolean result = backtracking(board);
if (result) return true;
board[i][j]='.';
}
}
//如果放哪个数都不可以,返回false
return false;
}
}
}
return true;
}
public boolean isvalid(int i,int j,char k,char[][] board){
//检查列
for (int m=0;m<board.length;m++){
if (board[m][j]==k) return false;
}
//检查行
for (int n=0;n<board[0].length;n++){
if (board[i][n]==k) return false;
}
//检查九宫格
//归一化到九宫格起点
int startrow = (i/3)*3;
int startcol = (j/3)*3;
for (int m=startrow;m<startrow+3;m++){
for (int n=startcol;n<startcol+3;n++){
if (board[m][n]==k) return false;
}
}
return true;
}
}
复杂度分析:
时间复杂度:
O
(
n
)
\mathcal{O}(n)
O(n)
空间复杂度:
O
(
1
)
\mathcal{O}(1)
O(1)