《仨》 简单算法--1.递归-下

149 阅读3分钟

本文已参与「新人创作礼」活动,一起开启掘金创作之路

(5) 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

N-皇后问题是可以通过回溯来解决,其实有点类似dfs递归寻找排列型枚举,排列型枚举本质上也是用到了回溯,即返回到上一个状态。N*N行格子,皇后无法在斜角和十字里遇到皇后,即每一行只能出现一个皇后,那我们就按行来进行枚举,在第一行放置完皇后后,将该点十字及斜角上的点都设置为可攻击的点,即设置为1,然后可以进入下一行,找到不是1的格子,放置皇后,同理及下,当遇到某一行不可放置皇后后,证明上一步是不可放置的点,则返回上一层寻找下一个可以放置的点,继续进行,若仍然无法放置皇后,则需要返回到可以放置的点后,才可以继续往下进行。

这里设计到的知识点是回溯,即回到上一个状态,那我们就需要将上一个状态记住,在无法到达或者下层已经搜寻结束,回到上一个状态。

这个过程遇到的问题有:

(1) List集合如何初始化,及如何构造二维List集合

如下:List<List l = new ArrayList<List();

初始化一维数组后,仍然需要初始化二维数组,这里我采用加入新的List

l.add(new ArrayList());

(2)数组的toString方法,并非是将数组内的元素转化为String类型,若要转化为String类型,需要使用String.valueOf(char[]);

(3)浅拷贝和深拷贝问题,若直接进行集合类直接的赋值的话,因为类是引用型变量,存的是指针(Java中无指针,只是借以说明),如果想要深拷贝的话,就涉及到ArrayList的构造函数,使用new ArrayList<>(List l),可以l为模板new 出一个新的ArrayList,且如果要使用到集合的copy函数的时候(collections.copy(desk,src)

//第一个参数是目的集合,第二个参数是源集合 static void copy(List<? super T> dest, List<? extends T> src) 将所有元素从一个列表复制到另一个列表中。

ArrayList声明时默认的元素个数是0,只有进行add(),remove()操作时size()的大小才有相应的变化。 进行集合复制时,一要声明目的集合的元素的个数,并且要等于或者大于源集合的元素的个数。 如果不声明或者小于源集合的元素个数,这样就会报错,报下标界的异常(java.lang.IndexOutOfBoundsException)。

 import java.io.*;
 import java.util.*;
 ​
 public class Main{
         static BufferedReader in = new BufferedReader(new InputStreamReader(System.in));
         static BufferedWriter out = new BufferedWriter(new OutputStreamWriter(System.out));
         public static int[] dx = {-1,1,0,0,-1,-1,1,1};
         public static int[] dy = {0,0,-1,1,-1,1,-1,1};
         public static List<List<String>> solveNQueens(int n){
             List<List<String>> solve = new ArrayList<List<String>>();
             List<List<Integer>> attack = new ArrayList<List<Integer>>();
             List<String> queen = new ArrayList<String>();
             char [] temp = new char[n];
             Arrays.fill(temp,'.');
             for(int i = 0; i < n; ++i) {
                 attack.add(new ArrayList<Integer>());
                 for(int j = 0; j < n; ++j) {
                     attack.get(i).add(0);
                 }
                 queen.add(String.valueOf(temp));
                 
             }
             backtrack(0,n,queen,attack,solve);
             return solve;
         }
         public static void backtrack(int k,int n,List<String> queen,
                 List<List<Integer>> attack,List<List<String>> solve) {
             if(k == n) {
                 solve.add(new ArrayList<String>(queen));
                 return ;
             }
             
             for(int i = 0; i < n; ++i) {
                 if(attack.get(k).get(i) == 0) {
                     //1.ArrayList构造函数的问题
                     //2.Collections.copy复制函数的问题
                     //3.如何将一个进行集合的深拷贝
                     List<List<Integer>> temp = new ArrayList<List<Integer>>();
                     for(int j = 0; j < n; ++j) {
                         temp.add(new ArrayList<Integer>(attack.get(j)));
                     }
                     queen.set(k, replaceString(queen.get(k),i,'Q'));
                     put_queen(k,i,attack);
                     backtrack(k + 1,n,queen,attack,solve);
                     queen.set(k, replaceString(queen.get(k),i,'.'));
                     Collections.copy(attack,temp);
                 }
             }
         }
         public static String replaceString(String s,int i,char c) {
             char[] array = s.toCharArray();
             array[i] = c;
             return String.valueOf(array);
         }
         public static void put_queen(int x,int y,List<List<Integer>> attack) {
             attack.get(x).set(y, 1);
             for(int i = 0; i < attack.size(); ++i) {
                 for(int j = 0; j < 8; ++j) {
                     int x1 = x + i * dx[j];
                     int y1 = y + i * dy[j]; 
                     if(x1 >= 0 && x1 < attack.size() && y1 >=0 && y1 < attack.size()) {
                         attack.get(x1).set(y1, 1);
                     }
                 }
             }
         }
     public static void main(String[] args) throws Exception{
         String[] str = in.readLine().split(" ");
         int n = Integer.parseInt(str[0]);
         List<List<String>> result = solveNQueens(n);
         for(List l: result) {
             for(int i = 0; i < l.size(); i++) {
                 out.write(l.get(i) + "\n");
             }
         }
         in.close();
         out.close();
     }
 ​
 }

\