【每日一题】Leetcode - 51.N皇后

题目

Leetcode - 51.N皇后

解题思路

回溯:遍历棋盘,每次选择一个格子放皇后,然后封掉皇后可行的路,再接着往下找可放皇后的格子,找不到了就回去重新找下一个

class Solution {

    private List<List<String>> resList = new ArrayList<>();

    public List<List<String>> solveNQueens(int n) {
        deepChoice(createMap(n), n, new ArrayList<>(), 0);
        return resList;
    }

    private char[][] createMap(int n){
        char[][] map = new char[n][n];
        for (int i = 0; i < n; i++) {
            Arrays.fill(map[i], '.');
        }
        return map;
    }

    private static class Pos{
        int i,j;

        public Pos(int i, int j) {
            this.i = i;
            this.j = j;
        }

        @Override
        public boolean equals(Object obj) {
            if (! (obj instanceof Pos)) {
                return false;
            }
            Pos objPos = (Pos)obj;
            return objPos.i == i && objPos.j == j;
        }
    }

    private void deepChoice(char[][] map, int n, List<Pos> posList, int startI) {
        for (int i = startI; i < map.length; i++) {
            for (int j = 0; j < map[0].length; j++) {
                if (map[i][j] == '.') {
                    posList.add(new Pos(i, j));
                    if (n - 1 == 0) {
                        char[][] map1 = createMap(map.length);
                        for (Pos pos: posList) {
                            map1[pos.i][pos.j] = 'Q';
                        }
                        List<String> tempList = new ArrayList<>();
                        for (int k = 0; k < map.length; k++) {
                            StringBuilder sb = new StringBuilder();
                            for (char ch: map1[k]) {
                                sb.append(ch);
                            }
                            tempList.add(sb.toString());
                        }
                        if (!resList.contains(tempList)) {
                            resList.add(tempList);
                        }
                        posList.remove(posList.size() - 1);
                        continue;
                    }
                    List<Pos> recover = new ArrayList<>();
                    toWhat(map, i, j, '#', recover);
                    deepChoice(map, n - 1, posList, i);
                    posList.remove(posList.size() - 1);
                    toWhat(map, i, j, '.', null);
                    // 恢复已经被占用的位置
                    for (Pos pos: recover) {
                        map[pos.i][pos.j] = '#';
                    }
                    map[i][j] = '.';
                }
            }
        }
    }

    private void toWhat(char[][] map, int i, int j, char ch, List<Pos> recover) {
        for (int tJ = 0; tJ < map.length; tJ++) {
            //  左右
            change(map, ch, recover, i, tJ);
            //  上下
            change(map, ch, recover, tJ, j);
            //  右上
            change(map, ch, recover, i + tJ, j + tJ);
            //  左下
            change(map, ch, recover, i - tJ, j - tJ);
            //  左上
            change(map, ch, recover, i + tJ, j - tJ);
            //  右下
            change(map, ch, recover, i - tJ, j + tJ);
        }
    }

    private void change(char[][] map, char ch, List<Pos> recover, int i, int j) {
        Pos temp = new Pos(i,j);
        if (temp.i < 0 || temp.i >= map.length || temp.j < 0 || temp.j >= map[0].length) {
            return;
        }
        // 要占用 且 该位置是已经被占用
        if (ch == '#' && map[temp.i][temp.j] == '#' && !recover.contains(temp)) {
            recover.add(temp);
            return;
        }
        map[temp.i][temp.j] = ch;
    }

}

在这里插入图片描述

优化

前面的方式是预占好位置,判断是否可坐,再恢复位置,其中预占位置和恢复位置花费了多余的时间,换个思路,不预占位置,每次判断该点的左上,正上,右上是否有皇后,就可以确定皇后是否可放在该位置,而且恢复也只需要恢复皇后占用的位置

class Solution {

    private final List<List<String>> resList = new ArrayList<>();

    public List<List<String>> solveNQueens(int n) {
        char[][] map = new char[n][n];
        for (int i = 0; i < n; i++) {
            Arrays.fill(map[i], '.');
        }
        deepChoice(map,0, n);
        return resList;
    }

    private void deepChoice(char[][] map, int startI, int n) {
        if (n == 0) {
            List<String> tempList = new ArrayList<>();
            for (char[] chars : map) {
                StringBuilder sb = new StringBuilder();
                for (char ch : chars) {
                    sb.append(ch);
                }
                tempList.add(sb.toString());
            }
            resList.add(tempList);
            return;
        }
        for (int i = startI; i < map.length; i++) {
            for (int j = 0; j < map[0].length; j++) {
                if (judgeCan(map, i, j)) {
                    map[i][j] = 'Q';
                    deepChoice(map, i + 1, n - 1);
                    map[i][j] = '.';
                }
            }
        }
    }

    private boolean judgeCan(char[][] map, int i, int j) {
        if (map[i][j] == 'Q') {
            return false;
        }
        // 正上
        int t = i - 1;
        while (t >= 0) {
            if (map[t--][j] == 'Q') {
                return false;
            }
        }
        // 左上
        t = 1;
        while (i - t >= 0 && j - t >= 0) {
            if (map[i - t][j - t] == 'Q') {
                return false;
            }
            t++;
        }
        // 右上
        t = 1;
        while (i - t >= 0 && j + t < map.length) {
            if (map[i - t][j + t] == 'Q') {
                return false;
            }
            t++;
        }
        return true;
    }

}

在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值