N皇后问题

原题 https://oj.leetcode.com/problems/n-queens/

这个题写了好久。。。

其实思路比较简单。在每一列上按顺序每一个位置放皇后,而前面已经放好的皇后位置对后面放的皇后的位置是有影响的,因此以后选择摆放位置时要遵守前面的约束。

流程基本是:先在第一列选择一个位置放皇后,然后在第二列选择位置时不能和第一列的皇后有冲突(在一条直线或对角线上),在第三列时不能与一二列有冲突,以此类推,直到找到最后一列符合条件的位置,结果记录下来,然后回溯找其他符合条件的位置;或者在第i列时发现没有任何一个位置符合条件,于是需要回溯到第i-1列去,在该列上换下一个位置,继续以上流程。

整个流程类似于深度优先搜索。用栈保存访问过的位置信息,实现回溯。


import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Stack;

public class Solution {
    private final char INIT = '#';
    
    public static void main(String[] a)
    {
    	for(String[]	ss :new Solution().solveNQueens(5))
    	{
    		for(String s : ss)
    			System.out.println(s);
    		System.out.println();
    	}
    }
   
    public List<String[]> solveNQueens(int n) {
        List<String[]> ll = new LinkedList<String[]>();
        char[][][] charsOnStep = new char[n+1][n][n];
        charsOnStep[0] = this.getChars(n);
        int pre = -1;		//上一步是第几步
        
        Stack<int[]> steps = new Stack<int[]>();		//用行,列值对来表示步骤
        	steps.push(new int[]{0,0});
        	pre = -1;
        	charsOnStep[1] = this.putQ(0, 0, charsOnStep[0]);
        	while(!steps.isEmpty())
        	{
        		int[] head = steps.peek();
        		int r,c;
        		if(pre >= head[1])		//回溯
        		{
        			r = head[0]+1;		//回溯时,要接着上次访问的行数+1的位置
        			c = head[1];
        			steps.pop();
        		}
        		else
        		{
        			r = 0;
        			c = head[1]+1;
        		}
        		int i =c;
        		for(;i<n; i++)			//列
        		{
        			boolean found = false;
        			pre = i;
                    for(int j = r;j<n; j++)		//行
                    {
                        char[][] temp = charsOnStep[i];
                        if(temp[j][i] == '#')
                        {
                        	charsOnStep[i+1] = putQ(j,i,temp);
                        	steps.push(new int[]{j,i});
                        	found = true;
                        	r = 0;		//这里需要把r重置为0,使下一列继续从0开始扫描
                        	break;
                        }
                        
                    }
                    if(!found)			//没找到,说明走到i列时不能走下去了,需要回溯
                    {
                    	break;
                    }
                    
        		}
        		if(i == n)		//已经走到最后了,记录结果,然后该回溯了
        		{
        			pre = i;
        			ll.add(ctoss(charsOnStep[n]));
        		}
        		
        	}
        
        return ll;
        
    }
    
    //用一个二维的字符数组构造字符串数组
    private String[] ctoss(char[][] cs)
    {
    	String[] re = new String[cs.length];
    	for(int i = 0;i<cs.length; i++)
    		re[i] = new String(cs[i]);
    	return re;
    }
    //在r行c列上放置Q,并依据此Q的位置更新其直线斜线上的点为'.'
    public char[][] putQ(int r, int c, char[][] cs)
    {
    	cs = copy(cs);
        cs[r][c] = 'Q';
        for(int i = 0;i<cs.length; i++)
            if(i != r)
                cs[i][c] = '.';
        for(int i = 1;i < cs.length-c;i++)
        {
            cs[r][c+i] = '.';
            if(r+i < cs.length)
                cs[r+i][c+i] = '.';
            if(r-i >= 0)
                cs[r-i][c+i] = '.';
        }
        return cs;
    }
    
    public char[][] copy(char[][] cs)
    {
        char[][] c = new char[cs.length][cs.length];
        for(int i = 0;i<cs.length; i++)
            for(int j = 0;j<cs.length; j++)
                c[i][j] = cs[i][j];
        return c;
    }
    
    //初始化一个字符的二维数组,初始值用#标记
    public char[][] getChars(int n)
    {
        char[][] cs = new char[n][n];
        for(int i = 0;i<n; i++)
            for(int j = 0;j<n; j++)
                cs[i][j] = INIT;
        return cs;
    }
}




  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值