【LeetCode】51.N皇后(回溯)

题目链接

51. N 皇后

题目描述

解题思路

1.经典回溯

普通八皇后问题只需要求出有多少种可行方案即可,而本题稍微更难一点,还需要把这些可行方案记录并打印。

之前也说到遇到递归问题,两件分析法宝:画出递归树以及函数栈!本题递归树如下:

遇到的问题如下

(1)回溯过程中递归返回条件的判断:如何判断两个皇后是否在一条斜线上?

一开始打算利用max(x,y)/min(x,y)进行判断,但是由于都是整数除法,存在一些情况是行不通的,遂放弃。

观察之后,可以发现有以下规律:

利用两个一维数组分别表示主对角线和副对角线。

//主对角线,当n=4的时候,一共有7个值,也就是2*n-1个值,因为数组索引必须大于等于0,所以当(x-y)<0的时候,还需要+2*n-1;
int main_dia[] = new int[2*n-1];
int counter_dia[] = new int[2*n-1];

(2)回溯代码的细节问题。

AC代码中,赋值为1的代码必须和for循环结束赋值为0的代码的位置是对称的,也就是要么两个都在for循环内,要么两个代码段都在for循环外,不能一里一外

AC代码

class Solution {    
    List<List<String>> ans = new ArrayList<>();
    void dfs(int x,int y,int[] x_valid,int[] y_valid,int[] main_dia,int[] counter_dia,int n,int board[][]){
        if(x == n) return;
        if(x_valid[x]==1) return;
        if(y_valid[y]==1) return;
        if(main_dia[x+y]==1) return;
        if(x-y<0&&counter_dia[x-y+2*n-1]==1) return;
        if(x-y>=0&&counter_dia[x-y]==1) return;
        if(x == n -1){
            List<String> temp = new ArrayList<>();
            board[x][y]=1;
            for(int i = 0; i < n; i++){
                StringBuffer sb = new StringBuffer();
                for(int j = 0; j < n; j++){
                    if(board[i][j]==1) sb.append("Q");
                    else sb.append(".");
                }
                temp.add(sb.toString());
            }
            ans.add(temp);
        }
        //这段赋值为1的代码必须和for循环结束赋值为0的代码的位置是对称的,也就是要么两个都在for循环内,要么两个代码段都在for循环外,不能一里一外
        x_valid[x]=1;
        y_valid[y]=1;
        main_dia[x+y]=1;
        board[x][y]=1;
        if(x-y<0) counter_dia[x-y+2*n-1] = 1;
        else counter_dia[x-y]=1;
        for(int i = 0; i < n; i++){
            dfs(x+1,i,x_valid,y_valid,main_dia,counter_dia,n,board);
        } 
        x_valid[x]=0;
        y_valid[y]=0;
        board[x][y]=0;
        main_dia[x+y]=0;
        if(x-y<0) counter_dia[x-y+2*n-1] = 0;
        else counter_dia[x-y]=0;
    }

    public List<List<String>> solveNQueens(int n) {
        int x_valid[] = new int[n];
        int y_valid[] = new int[n];
        int main_dia[] = new int[2*n-1];
        int counter_dia[] = new int[2*n-1];
        int board[][] = new int[n][n];
        for(int i = 0; i < n; i++){
            dfs(0,i,x_valid,y_valid,main_dia,counter_dia,n,board);
        }
        return ans;
    }
}
posted @ 2020-09-03 23:36  控球强迫症  阅读(109)  评论(0编辑  收藏  举报