面试题 08.12. N皇后

题目

设计一种算法,打印 N 皇后在 N × N 棋盘上的各种摆法,其中每个皇后都不同行、不同列,也不在对角线上。这里的“对角线”指的是所有的对角线,不只是平分整个棋盘的那两条对角线。

注意:本题相对原题做了扩展

示例:

输入:4
输出:[[".Q..","...Q","Q...","..Q."],["..Q.","Q...","...Q",".Q.."]]
解释: 4 皇后问题存在如下两个不同的解法。
[
 [".Q..",  // 解法 1
  "...Q",
  "Q...",
  "..Q."],

["..Q.",  // 解法 2
  "Q...",
  "...Q",
  ".Q.."]
]

分析

这道题用回溯法的思路很清晰,重点在于如何判断当前放置棋子的位置是否合理。按行依次落子,定义一个数组pre记录已经落子的位置。因为按行的顺序落子,所以同一行不会出现冲突,行不用检查。因此只用遍历pre数组,检查是否有行冲突和对角线冲突即可。若两个位置在同一对角线,它们行序号之差的绝对值=列序号之差的绝对值。

代码

class Solution {
    private List<List<String>> res=new ArrayList<>();
    private int[] pre;
    boolean isValid(int row,int col){
        for(int i=0;i<row;++i)
            if(col==pre[i]||Math.abs(row-i)==Math.abs(col-pre[i])) return false;
        return true;
    }
    //ans代表了当前节点的状态
    public void backtrack(int cur,int n,List<String> ans){
        if(cur==n){
            //添加不同元素要用不同的引用!!!
            //因此不能直接添加ans
            res.add(new ArrayList<>(ans));
            return; 
        }
        for(int i=0;i<n;++i){
            if(isValid(cur,i)){
                pre[cur]=i;
                String s=ans.get(cur);
                s=s.substring(0,i)+"Q"+s.substring(i+1);
                ans.set(cur,s);
                backtrack(cur+1,n,ans);
                //还原状态
                s=s.substring(0,i)+"."+s.substring(i+1);
                ans.set(cur,s);
            }
        }
    }
    public List<List<String>> solveNQueens(int n) {
        //初始化棋盘,所有位置都是'.'
        char[] c=new char[n];
        Arrays.fill(c,'.');
        List<String> list=Collections.nCopies(n,new String(c));
        List<String> ans=new ArrayList<>(list);
        //pre[i]表示第i行棋子所在的列序号
        pre=new int[n];
        backtrack(0,n,ans);
        return res;
    }
}

原题链接:https://leetcode-cn.com/problems/eight-queens-lcci

posted @ 2021-01-02 00:46  归鸿唱晚  阅读(60)  评论(0编辑  收藏  举报