[LeetCode 51] N皇后

题目描述

在这里插入图片描述
示例:

输入: 4
输出: [
[".Q…", // 解法 1
“…Q”,
“Q…”,
“…Q.”],

["…Q.", // 解法 2
“Q…”,
“…Q”,
“.Q…”]
]
解释: 4 皇后问题存在两个不同的解法。

题目分析

这个N皇后其实和数独有异曲同工的地方,皇后不能互相攻击的意思就在同一行同一列以及两条对角线上不能由其他的皇后,否则就将不符合题意。和数独同样的思路,设三个数组,默认为是fault,如果插入数组,那么就同行同列,以及对角线都为true。最后根据数组的索引插入"Q"或者"."。同样的,用回溯算法,既然不知道第几次能完全插入正确,那就一个一个的试了,直到正确为止。

源码

class Solution {
List<List<String>> result=new LinkedList<>();
public List<List<String>> solveNQueens(int n) {
    LinkedList<Integer> res=new LinkedList<>();
    //保存已经访问过的地址
    boolean[] col=new boolean[n];
    boolean[] main_diag=new boolean[2*n];
    boolean[] anti_diag=new boolean[2*n];
    //2n就是因为对角线长度的计算
    dfs(res,col,main_diag,anti_diag,0,n);
    return result;
}
private void dfs(LinkedList<Integer> res,boolean[] col,boolean[] main_diag,boolean[] anti_diag,int row,int n){
    if(row==n){
    //回溯结束的标志,就是全部遍历完了
        List<String> list=new LinkedList<>();
        for(int i=0;i<n;i++){
            StringBuilder sb=new StringBuilder();
            for(int j=0;j<n;j++){
               sb.append(res.get(i) == j ? "Q" : ".");
               //如果是已经保存的地址,那么填'Q'不然就是'.'
            }
            list.add(sb.toString());
        }
        result.add(list);
        return;
    }
    for(int i=0;i<n;i++){
        if(col[i]||main_diag[row+i]||anti_diag[row-i+n]){
            continue;
        }
        res.add(i);
        col[i]=true;
        main_diag[i+row]=true;
        anti_diag[row-i+n]=true;
        dfs(res,col,main_diag,anti_diag,row+1,n);
        //递归
        res.removeLast();
        //回溯
        col[i]=false;
        main_diag[row+i]=false;
        anti_diag[row-i+n]=false;
    }
}
}

难点

这道题最首先的难点就是理解题意,没玩过象棋的还真不知道互相攻击是什么意思,仅仅误解为行列不能相同那就惨了。
其次,要比数独多一个索引的链表,当然了 如果用数独的二维数组也可以,这样可以少一个索引链表但是多一个参数row[n][n]。

改进

这道题是很经典的回溯题,那么有没有办法再简化一下上面的代码呢?其实是可以的,不过就是把判断是否合法的方式不用数组表示,而是用链表的地址判断。当然对角线的地址仍然是row-i以及row-i+n

改进代码

class Solution {
public List<List<String>> solveNQueens(int n) {
    List<List<String>> res = new ArrayList<List<String>>();
    solveNQueensDFS(0,n,res,new ArrayList<>());
    return res;
}

public void solveNQueensDFS(int row,int n,List<List<String>> res,List<String> tmp){
    if(row == n){
        res.add(new ArrayList<>(tmp));
        return;
    }
    //根据Q的位置生成String
    String line;
    for(int i = 0;i < n;i++){
        line = "";
        for(int j = 0;j<n;j++){
            if(j==i) line += 'Q';
            else line += '.';
        }
        //判断是否符合规则
        if(isQ(tmp,line)){
            tmp.add(line);
            solveNQueensDFS(row+1,n,res,tmp);
            tmp.remove(tmp.size()-1);
        }

    }
}

public boolean isQ(List<String> tmp ,String s){
    if(tmp.size() == 0) return true;
    //获取tmp中每个Q的位置
    ArrayList<Integer> check = new ArrayList<>();
    for(String t : tmp){
        check.add(t.indexOf('Q'));
    }
    int index = s.indexOf('Q');
    if(check.contains(index)) return false;
    //判断对角线
    for (int i =0;i<check.size();i++){
        int row =check.get(i);
        if( index == row + (check.size()-i) || index == row - (check.size()-i))
            return false;
    }
    return true;
}

}

分析

时间复杂度都为O(n!)

小结

对于同行同列或者同对角线不能出现相同的数据的这类题目,思路就是设个boolean的数组,被索引了或者访问了就设为true,如果第二次被访问了那就直接报错就行啦。

[1]https://leetcode-cn.com/problems/n-queens/

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值