51. N-Queens

N皇后问题求解

题意:n-皇后问题,即将n个皇后放到n*n的棋盘上满足任意两个皇后都不能攻击彼此,皇后一步能攻击其他同行、同列或者同对角线的皇后

要求:输入维度整数n,返回n皇后问题的所有不同的方案,每种方案是不同的放置布局,其中‘Q’和‘.’分别表示皇后和 空白空间。

思路:1、从结果来看,每列只有一个皇后,每行只有一个皇后。选择从行考虑(或者从列考虑,由对称性知,会得到相同的结果),使用的数据结构stack。

            2、如何判断后面的位置能否放置皇后?1 每次放置一个皇后,根据其位置将后面不能放置的位置放到哈希表(排除的位置表)中。

           3、如何判断不能放置的位置,即同行、同列、同对角线?采用ax+by+c=0。具体的,x=x0,y=y0,y=+-x + c0

public class Solution {
  public List> solveNQueens(int n) {
        List> solToString = new LinkedList<>();
        List> sols = new LinkedList<>(); 
        ArrayList path = new ArrayList<>(n);
        nQueensComplete(sols, path, n, 0);
       // addNQueens(sols, path, n, 0);
        solsToStr(sols, solToString, n);
        return solToString;
    }
    
    private void nQueensComplete(List> sols, ArrayList path, int n, int i) {
    	addNQueens(sols, path, n, 0);
		mirrored(sols, n);
	}

	private void mirrored(List> sols, int n){
		LinkedList> mirrorSols = new LinkedList<>();
		for(List sol : sols){
			ArrayList mirror = new ArrayList<>(n);
			Coordinate queen = sol.get(0); //首行的元素
			if(n % 2 == 1 && queen.y == (n-1)/2){ //正中间的处理,避免重复
				continue;
			}
			mirror.add(new Coordinate(queen.x, (n-1)-queen.y));
			
			for(int i = 1; i < sol.size(); i++){
				queen = sol.get(i);
				Coordinate mirQueen = new Coordinate(queen.x, (n-1)-queen.y);
				mirror.add(mirQueen);
			}
			mirrorSols.addFirst(mirror);
		}
		sols.addAll(mirrorSols);
    }
	
    private void solsToStr(List> sols, List> solToString, int n) {
    	for(List sol : sols){ 
    		ArrayList nQueenToStr = new ArrayList<>(n); 
    		for(Coordinate queen : sol){//按行存
    			String s = "";
    			for(int col = 0; col < n; col++){
    				if(col != queen.y){
    					s += ".";
    				}else{
    					s += "Q";
    				}
    			}
    			nQueenToStr.add(s);
    		}
    		solToString.add(nQueenToStr);
    	}
	}
    
	private void addNQueens(List> sols, ArrayList path, int n, int startRow) {
	
		for(int col = 0; col < n; col++){
			if(startRow == 0 && col >= (n+1)/2)//根据对称性将搜索减半
				return;
			Coordinate startPoint = new Coordinate(startRow, col);
			for(int i = path.size()-1; i >= startRow; i--){
				path.remove(i);
			}
			if(!testPoint(path, startPoint))
				continue;
			path.add(startPoint);
			
			if(startRow == (n-1)){
				sols.add(new ArrayList<>(path));
				return;
			}
			addNQueens(sols, path, n, startRow+1);
		}
	}


	private boolean testPoint(ArrayList path, Coordinate startPoint) {
		for(Coordinate queen : path){
			if(queen.x == startPoint.x || queen.y == startPoint.y){
				return false;
			}
			if(startPoint.y - queen.y == startPoint.x - queen.x) //k=1
				return false;
			if(startPoint.y - queen.y == queen.x - startPoint.x)
				return false;
		}
		return true;
	}


	public static class Coordinate{
    	int x;
    	int y;
		public Coordinate(int x, int y) {
			super();
			this.x = x;
			this.y = y;
		}
		@Override
		public int hashCode() {
			final int prime = 31;
			int result = 1;
			result = prime * result + x;
			result = prime * result + y;
			return result;
		}
		@Override
		public boolean equals(Object obj) {
			if (this == obj)
				return true;
			if (obj == null)
				return false;
			if (getClass() != obj.getClass())
				return false;
			Coordinate other = (Coordinate) obj;
			if (x != other.x)
				return false;
			if (y != other.y)
				return false;
			return true;
		}
    }
	
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值