N皇后问题
/**
* 如何判断是否是对角线,对应坐标相减结果绝对值相等则对角线: Math.abs(x1 - x2) == Math.abs(y1 - y2);
*/
N皇后第一版代码:性能较差,但是完全由自己写粗来的,基于此版本优化:
package com.javartisan.redpacket; import java.util.ArrayList; import java.util.HashSet; import java.util.List; /** * 如何判断是否是对角线,对应坐标相减结果绝对值相等则对角线: Math.abs(x1 - x2) == Math.abs(y1 - y2); */ class Solution { public static List<List<String>> solveNQueens(int n) { List<List<String>> ans = new ArrayList<>(); byte[][] mtx = new byte[n][n]; ArrayList<String> an = new ArrayList<>(); for (int i = 0; i < n; i++) { an.add(""); } trace(ans, an, n, n, mtx); HashSet<List<String>> set = new HashSet<>(ans); return new ArrayList<>(set); } public static void trace(List<List<String>> ans, ArrayList<String> an, int n, int cur, byte[][] mtx) { if (cur == 0) { ans.add((List<String>) an.clone()); return; } for (int i = 0; i < n; i++) { for (int j = 0; j < n; j++) { if (check(mtx, i, j, n)) { mtx[i][j] = 1; StringBuilder sb = new StringBuilder(); for (int k = 0; k < n; k++) { if (k == j) { sb.append("Q"); } else { sb.append("."); } } an.set(i, sb.toString()); trace(ans, an, n, --cur, mtx); an.set(i, ""); mtx[i][j] = 0; cur++; } } } } public static boolean check(byte[][] mtx, int x, int y, int n) { boolean status = true; for (int i = 0; i < n && status; i++) { if (mtx[x][i] == 1) { status = false; break; } } for (int i = 0; i < n && status; i++) { if (mtx[i][y] == 1) { status = false; break; } } for (int i = x, j = y; i > 0 && j > 0 && status; i--, j--) { if (mtx[i - 1][j - 1] == 1) { status = false; break; } } for (int i = x, j = y; i < n - 1 && j < n - 1 && status; i++, j++) { if (mtx[i + 1][j + 1] == 1) { status = false; break; } } for (int i = x, j = y; i < n - 1 && j > 0 && status; i++, j--) { if (mtx[i + 1][j - 1] == 1) { status = false; break; } } for (int i = x, j = y; i > 0 && j < n - 1 && status; i--, j++) { if (mtx[i - 1][j + 1] == 1) { status = false; break; } } return status; } public static void main(String[] args) { byte[][] mtx = { {0, 0, 1, 0}, {0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0}, }; int n =7; long start = System.currentTimeMillis(); System.out.println(solveNQueens(n)); System.out.println(System.currentTimeMillis() - start); System.out.println(solveNQueens(n).size()); } }
简单优化版:
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
/**
* 如何判断是否是对角线,对应坐标相减结果绝对值相等则对角线: Math.abs(x1 - x2) == Math.abs(y1 - y2);
*/
class Solution {
public static List<List<String>> solveNQueens(int n) {
byte[] x = new byte[n];
byte[] y = new byte[n];
List<List<String>> ans = new ArrayList<>();
byte[][] mtx = new byte[n][n];
ArrayList<String> an = new ArrayList<>();
for (int i = 0; i < n; i++) {
an.add("");
}
trace(ans, an, n, n, mtx, x, y);
HashSet<List<String>> set = new HashSet<>(ans);
return new ArrayList<>(set);
}
public static void trace(List<List<String>> ans, ArrayList<String> an, int n, int cur, byte[][] mtx, byte[] usedX, byte[] usedY) {
if (cur == 0) {
ans.add((List<String>) an.clone());
return;
}
for (int i = 0; i < n; i++) {
if (usedX[i] == 1) {
continue;
}
for (int j = 0; j < n; j++) {
if (usedY[j] != 1 && check(mtx, i, j, n)) {
mtx[i][j] = 1;
usedX[i] = 1;
usedY[j] = 1;
StringBuilder sb = new StringBuilder();
for (int k = 0; k < n; k++) {
if (k == j) {
sb.append("Q");
} else {
sb.append(".");
}
}
an.set(i, sb.toString());
trace(ans, an, n, --cur, mtx, usedX, usedY);
an.set(i, "");
mtx[i][j] = 0;
usedX[i] = 0;
usedY[j] = 0;
cur++;
}
}
}
}
public static boolean check(byte[][] mtx, int x, int y, int n) {
boolean status = true;
for (int i = 0; i < n && status; i++) {
if (mtx[x][i] == 1) {
status = false;
break;
}
}
for (int i = 0; i < n && status; i++) {
if (mtx[i][y] == 1) {
status = false;
break;
}
}
for (int i = x, j = y; i > 0 && j > 0 && status; i--, j--) {
if (mtx[i - 1][j - 1] == 1) {
status = false;
break;
}
}
for (int i = x, j = y; i < n - 1 && j < n - 1 && status; i++, j++) {
if (mtx[i + 1][j + 1] == 1) {
status = false;
break;
}
}
for (int i = x, j = y; i < n - 1 && j > 0 && status; i++, j--) {
if (mtx[i + 1][j - 1] == 1) {
status = false;
break;
}
}
for (int i = x, j = y; i > 0 && j < n - 1 && status; i--, j++) {
if (mtx[i - 1][j + 1] == 1) {
status = false;
break;
}
}
return status;
}
public static void main(String[] args) {
byte[][] mtx = {
{0, 0, 1, 0},
{0, 0, 0, 0},
{0, 0, 0, 0},
{0, 0, 0, 0},
};
System.out.println(solveNQueens(4).size());
int n = 7;
long start = System.currentTimeMillis();
System.out.println(solveNQueens(n));
System.out.println(System.currentTimeMillis() - start);
start = System.currentTimeMillis();
System.out.println(solveNQueens(8).size());
System.out.println(System.currentTimeMillis() - start);
}
}
优化第三版:
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
/**
* 如何判断是否是对角线,对应坐标相减结果绝对值相等则对角线: Math.abs(x1 - x2) == Math.abs(y1 - y2);
*/
class Solution {
StringBuilder sb = null;
byte[] mx = null;
byte[] my = null;
public List<List<String>> solveNQueens(int n) {
List<List<String>> ans = new ArrayList<>(n);
byte[][] mtx = new byte[n][n];
ArrayList<String> an = new ArrayList<>(n);
sb=new StringBuilder(n);
for (int i = 0; i < n; i++) {
an.add("");
sb.append(".");
}
mx = new byte[n];
my = new byte[n];
trace(ans, an, n, n, mtx, 0);
return ans;
}
public void trace(List<List<String>> ans, ArrayList<String> an, int n, int cur, byte[][] mtx, int x) {
if (cur == 0) {
ans.add((List<String>) an.clone());
return;
}
for (int i = x; i < n; i++) {
if (mx[i] == 1) {
continue;
}
for (int j = 0; j < n; j++) {
if (my[j] != 1 && check(mtx, i, j, n)) {
mtx[i][j] = 1;
mx[i] = 1;
my[j] = 1;
StringBuilder builder = new StringBuilder(this.sb);
builder.setCharAt(j, 'Q');
an.set(i, builder.toString());
trace(ans, an, n, --cur, mtx, i+1);
an.set(i, "");
mtx[i][j] = 0;
mx[i] = 0;
my[j] = 0;
cur++;
}
}
}
}
public boolean check(byte[][] mtx, int x, int y, int n) {
for (int i = 0; i < n; i++) {
if (mtx[x][i] == 1) {
return false;
}
}
for (int i = 0; i < n; i++) {
if (mtx[i][y] == 1) {
return false;
}
}
for (int i = x, j = y; i > 0 && j > 0; i--, j--) {
if (mtx[i - 1][j - 1] == 1) {
return false;
}
}
for (int i = x, j = y; i < n - 1 && j < n - 1; i++, j++) {
if (mtx[i + 1][j + 1] == 1) {
return false;
}
}
for (int i = x, j = y; i < n - 1 && j > 0; i++, j--) {
if (mtx[i + 1][j - 1] == 1) {
return false;
}
}
for (int i = x, j = y; i > 0 && j < n - 1; i--, j++) {
if (mtx[i - 1][j + 1] == 1) {
return false;
}
}
return true;
}
public static void main(String[] args) {
byte[][] mtx = {
{0, 0, 1, 0},
{0, 0, 0, 0},
{0, 0, 0, 0},
{0, 0, 0, 0},
};
// System.out.println(check(mtx, 1, 3, 4));
//
// for (int i = 0; i < 4; i++) {
// for (int j = 0; j < 4; j++) {
// System.out.println("i = " + i + " j = " + j + " " + check(mtx, i, j, 4));
// }
// }
System.out.println(new Solution().solveNQueens(4));
}
}

不超时可以通过了。
优化第4版本,对于当前i,j判断当前行与列是否允许放皇后通过mx,my 单个坐标进行判断,而不是使用二维矩阵:
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
/**
* 如何判断是否是对角线,对应坐标相减结果绝对值相等则对角线: Math.abs(x1 - x2) == Math.abs(y1 - y2);
*/
class Solution {
StringBuilder sb = null;
byte[] mx = null;
byte[] my = null;
public List<List<String>> solveNQueens(int n) {
List<List<String>> ans = new ArrayList<>(n);
byte[][] mtx = new byte[n][n];
ArrayList<String> an = new ArrayList<>(n);
sb=new StringBuilder(n);
for (int i = 0; i < n; i++) {
an.add("");
sb.append(".");
}
mx = new byte[n];
my = new byte[n];
trace(ans, an, n, n, mtx, 0);
return ans;
}
public void trace(List<List<String>> ans, ArrayList<String> an, int n, int cur, byte[][] mtx, int x) {
if (cur == 0) {
ans.add((List<String>) an.clone());
return;
}
for (int i = x; i < n; i++) {
if (mx[i] == 1) {
continue;
}
for (int j = 0; j < n; j++) {
if (my[j] != 1 && check(mtx, i, j, n)) {
mtx[i][j] = 1;
mx[i] = 1;
my[j] = 1;
StringBuilder builder = new StringBuilder(this.sb);
builder.setCharAt(j, 'Q');
an.set(i, builder.toString());
trace(ans, an, n, --cur, mtx, i+1);
an.set(i, "");
mtx[i][j] = 0;
mx[i] = 0;
my[j] = 0;
cur++;
}
}
}
}
public boolean check(byte[][] mtx, int x, int y, int n) {
/*
for (int i = 0; i < n; i++) {
if (mtx[x][i] == 1) {
return false;
}
}
for (int i = 0; i < n; i++) {
if (mtx[i][y] == 1) {
return false;
}
}
*/
for (int i = x, j = y; i > 0 && j > 0; i--, j--) {
if (mtx[i - 1][j - 1] == 1) {
return false;
}
}
for (int i = x, j = y; i < n - 1 && j < n - 1; i++, j++) {
if (mtx[i + 1][j + 1] == 1) {
return false;
}
}
for (int i = x, j = y; i < n - 1 && j > 0; i++, j--) {
if (mtx[i + 1][j - 1] == 1) {
return false;
}
}
for (int i = x, j = y; i > 0 && j < n - 1; i--, j++) {
if (mtx[i - 1][j + 1] == 1) {
return false;
}
}
return true;
}
public static void main(String[] args) {
byte[][] mtx = {
{0, 0, 1, 0},
{0, 0, 0, 0},
{0, 0, 0, 0},
{0, 0, 0, 0},
};
// System.out.println(check(mtx, 1, 3, 4));
//
// for (int i = 0; i < 4; i++) {
// for (int j = 0; j < 4; j++) {
// System.out.println("i = " + i + " j = " + j + " " + check(mtx, i, j, 4));
// }
// }
System.out.println(new Solution().solveNQueens(4));
}
}

浙公网安备 33010602011771号