leetcode-051-n皇后

题目及测试

package pid051;
/*51. N 皇后
按照国际象棋的规则,皇后可以攻击与之处在同一行或同一列或同一斜线上的棋子。

n 皇后问题 研究的是如何将 n 个皇后放置在 n×n 的棋盘上,并且使皇后彼此之间不能相互攻击。

给你一个整数 n ,返回所有不同的 n 皇后问题 的解决方案。

每一种解法包含一个不同的 n 皇后问题 的棋子放置方案,该方案中 'Q' 和 '.' 分别代表了皇后和空位。

 

示例 1:


输入:n = 4
输出:[[".Q..","...Q","Q...","..Q."],["..Q.","Q...","...Q",".Q.."]]
解释:如上图所示,4 皇后问题存在两个不同的解法。
示例 2:

输入:n = 1
输出:[["Q"]]
 

提示:

1 <= n <= 9
*/

import java.util.List;

public class main {
	
	public static void main(String[] args) {
		int[] testTable = {4,1,5,3,6,4};
		for (int ito : testTable) {
			test(ito);
		}
	}
		 
	private static void test(int ito) {
		Solution solution = new Solution();
		List<List<String>> rtn;
		long begin = System.currentTimeMillis();
		
		System.out.print(ito+" ");		    
		
		System.out.println();
		//开始时打印数组
		
		rtn = solution.solveNQueens(ito);//执行程序
		long end = System.currentTimeMillis();	
		
		//System.out.println(ito + ": rtn=" + rtn);
		System.out.println( " rtn=" );
		for (int i = 0; i < rtn.size(); i++) {
		    List<String> now=rtn.get(i);
		    for(int j=0;j<now.size();j++){
		    	System.out.print(now.get(j)+" ");
		    }
		    System.out.println();
		}//打印结果几数组
		
		System.out.println();
		System.out.println("耗时:" + (end - begin) + "ms");
		System.out.println("-------------------");
	}

}

解法1(成功,2ms,极快)

本题也是回溯算法的经典题目。N 皇后问题也是一个暴力穷举的问题。
其实题目可以改成,在每一行放置一个皇后,让这些皇后不能相互攻击。(因为每一行最多只有一个皇后)
我们可以先不考虑每一个皇后之间不能相互攻击的条件,如果要求每行只能放一个皇后,我们能否穷举出所有的放置方法?
考虑皇后之间相互攻击的问题
对于每一个格子进行计算分析能不能放置皇后,最后的代码实现会跳过这些格子,把皇后放在合法的位置上。
具体的,在每一个位置放置皇后,然后调用 backtrack 函数,进入下一行进行穷举进行判断
isValid 函数的逻辑
按照题意我们需要检查八个方向是否有其他方向,但实际上我们只需要检查三个方向即可。
因为我们的逻辑是每一行只放一个皇后,所以这个皇后的左边和右边不需要进行检查了。
因为我们是一行一行从上向下放置皇后,所以下方,左下方和右下方不会有皇后(还没放皇后)。
最后我们需要检查的只有上方、左上和右上三个方向。
斜方向45度,只需target-i=span,然后看target-queens[i]是否等于+-span即可。
函数 backtrack 依然像个在决策树上游走的指针,每个节点就表示在 board[row][col] 上放置皇后,通过 isValid 函数可以将不符合条件的情况剪枝。

package pid051;

import java.util.ArrayList;
import java.util.List;


class Solution {
    public List<List<String>> solveNQueens(int n) {
    	List<List<String>> result = new ArrayList<>();
    	if(n<=0){
    		return null;
    	}
    	int[] nowQueens = new int[n];
    	dfs(nowQueens,0,result);
    	return result;
    }
    
    private void dfs(int[] nowQueens,int index,List<List<String>> result){
    	if(index == nowQueens.length){
    		result.add(createResult(nowQueens));
    		return;
    	}
    	for(int i=0;i<nowQueens.length;i++){
    		nowQueens[index]=i;
    		if(testQueens(nowQueens,index)){
    			dfs(nowQueens, index+1, result);
    		}
    	}
    }
    
    private boolean testQueens(int[] queens,int index){
    	if(index == 0){
    		return true;
    	}
    	int target = queens[index];
    	for(int i=0;i<index;i++){
    		int now = queens[i];
    		if(now == target){
    			return false;
    		}
    		int span = index-i;
    		if(now+span==target){
    			return false;
    		}
    		if(now-span==target){
    			return false;
    		}
    	}
    	return true;
    }
    
    private List<String> createResult(int[] nowQueens){
    	List<String> result = new ArrayList<>();
    	int length = nowQueens.length;
    	for(int i=0;i<length;i++){
    		StringBuilder nowBuilder = new StringBuilder();
    		for(int j=0;j<nowQueens[i];j++){
    			nowBuilder.append('.');
    		}
    		nowBuilder.append('Q');
    		for(int j=nowQueens[i]+1;j<length;j++){
    			nowBuilder.append('.');
    		}
    		result.add(nowBuilder.toString());
    	}
    	return result;
    }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值