N-Queens N皇后问题@LeetCode

时间:2022-04-10 11:07:46

经典的8皇后,递归回溯可解。同时还学了StringBuilder里面一个setCharAt()很方便的方法。


package Level4;
import java.util.ArrayList;
import java.util.Arrays;

/**
*
* N-Queens
*
* The n-queens puzzle is the problem of placing n queens on an n×n chessboard such that no two queens attack each other.

http://www.leetcode.com/wp-content/uploads/2012/03/8-queens.png

Given an integer n, return all distinct solutions to the n-queens puzzle.

Each solution contains a distinct board configuration of the n-queens' placement, where 'Q' and '.' both indicate a queen and an empty space respectively.

For example,
There exist two distinct solutions to the 4-queens puzzle:

[
[".Q..", // Solution 1
"...Q",
"Q...",
"..Q."],

["..Q.", // Solution 2
"Q...",
"...Q",
".Q.."]
]
*
*/
public class S51 {

public static void main(String[] args) {
System.out.println(solveNQueens(4));
}

public static ArrayList<String[]> solveNQueens(int n) {
ArrayList<String[]> ret = new ArrayList<String[]>();
int[] queenList = new int[n];
placeQueen(queenList, 0, n, ret);
return ret;
}

// 递归回溯8皇后,关键记录下到达了哪一行了
public static void placeQueen(int[] queenList, int row, int n, ArrayList<String[]> ret){
// Base Case, 已经完成任务了
if(row == n){
StringBuilder[] sol = new StringBuilder[n];

// 对数组内每一个对象都要new出其对象
for(int i=0; i<n; i++){
sol[i] = new StringBuilder();
for(int j=0; j<n; j++){
sol[i].append(".");
}
}
// 在相应的地方放置queen
for(int i=0; i<n; i++){
sol[i].setCharAt(queenList[i], 'Q');
}
String[] ss = new String[n];
for (int i=0; i<n; i++) {
ss[i] = sol[i].toString();
}
ret.add(ss);
return;
}

// 开始这一行的查找
// 遍历第row行的所有列,测试哪一个位置是安全的
for(int col=0; col<n; col++){
if(isSafe(queenList, row, col)){
queenList[row] = col;
placeQueen(queenList, row+1, n, ret);
}
}
}

// 判断是否坐标(row,col)的位置是安全的(检查行,列,正反对角线)
// queenList里面存放行,列坐标pair,即queenList[row] = col
public static boolean isSafe(int[] queenList, int row, int col){
for(int preRow=0; preRow<row; preRow++){
int preCol = queenList[preRow];
if(preRow == row){ // 理论上不必检查,因为preRow是总是小于row的
return false;
}
if(preCol == col){ // 检查是否在同一列
return false;
}
if(row-preRow == col-preCol){ // 反对角线
return false;
}
if(preRow+preCol == row+col){ // 正对角线
return false;
}
}
return true;
}
}


这道题因为要求出全部可能,所以rec函数就没有返回值。如果只要求出一种,返回值就设为boolean,在里面当检查到一种情况为true时就直接返回,只有当检查完所有可能性后才return false (比如sudoku solver)

public class Solution {        public static List<String[]> solveNQueens(int n) {        List<String[]> list = new ArrayList<String[]>();        StringBuilder[] sb = new StringBuilder[n];        String s = "";        for(int i=0; i<n; i++) {            s += ".";        }        for(int i=0; i<n; i++) {            sb[i] = new StringBuilder(s);        }        rec(list, sb, n, 0);        return list;    }        public static void rec(List<String[]> list, StringBuilder[] sb, int n, int level) {        if(level == n) {            String[] ss = new String[n];            for(int i=0; i<n; i++) {                ss[i] = sb[i].toString();            }            list.add(ss);            return;        }                for(int j=0; j<n; j++) {            sb[level].setCharAt(j, 'Q');            if(isValid(sb)) {                rec(list, sb, n, level+1);            }                        sb[level].setCharAt(j, '.');        }    }        public static boolean isValid(StringBuilder[] sb) {        // print(sb);        for(int x1=0; x1<sb.length; x1++) {            for(int x2=x1+1; x2<sb.length; x2++) {                int y1 = sb[x1].indexOf("Q");                int y2 = sb[x2].indexOf("Q");                                if(y1 == -1 || y2 == -1) {                    continue;                }                    if(y1 == y2 || Math.abs(x1-x2) == Math.abs(y1-y2)) {                    return false;                }            }        }        return true;    }        public static void print(StringBuilder[] sb) {        for(int i=0; i<sb.length; i++) {            for(int j=0; j<sb[i].length(); j++) {                System.out.print(sb[i].charAt(j));            }            System.out.println();        }        System.out.println("=============");    }}