Leetcode之回溯法专题-51. N皇后(N-Queens)

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

上图为 8 皇后问题的一种解法。

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

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

示例:

输入: 4
输出: [
[".Q..", // 解法 1
"...Q",
"Q...",
"..Q."], ["..Q.", // 解法 2
"Q...",
"...Q",
".Q.."]
]
解释: 4 皇后问题存在两个不同的解法。 分析:输入一个N,求在这个N*N的面板里,N皇后的解法。要求是,放置了一个皇后时,该皇后的 行 列 不能存在其他皇后,且2个对角线上也不能有皇后。
利用回溯法可以解答这一题,首先初始化一个N*N的数组,并在其值上设置成'.'。
char mp[][] = new char[n][n];
for (int i = 0; i < n; i++) {
for (int j = 0; j < n; j++) {
mp[i][j] = '.';
}
}
然后我们new一个存答案的List,
List<List<String>> ans = new ArrayList<>();

在写DFS之前,我们需要写一个boolean型的ok函数,用于判断一个棋盘是否符合要求:
public boolean ok(char[][] mp, int len, int x, int y) {
// check row
for (int i = 0; i < len; i++) {
if (i == y)
continue;
if (mp[x][i] == 'Q')
return false;
} // check col
for (int i = 0; i < len; i++) {
if (i == x)
continue;
if (mp[i][y] == 'Q')
return false;
} // x=1 y=3
int cnt = 0;
int up = 0;
int down = 0; for(int i=y+1;i<len;i++){
up = (++cnt)*-1+x;
down = cnt*1+x; if(up<len && up>=0){
//System.out.println("mp[up][i]=["+up+"]["+i+"]");
if(mp[up][i]=='Q')
return false;
} if(down>=0 && down<len){
//System.out.println("mp[down][i]=["+down+"]["+i+"]");
if(mp[down][i]=='Q'){
return false;
}
}
} //System.out.println("other");
cnt = 0;
for(int i=y-1;i>=0;i--){
up = (++cnt)*-1+x;
down = cnt*1+x; if(up<len && up>=0){
//System.out.println("mp[up][i]=["+up+"]["+i+"]");
if(mp[up][i]=='Q')
return false;
} if(down>=0 && down<len){
//System.out.println("mp[down][i]=["+down+"]["+i+"]");
if(mp[down][i]=='Q'){
return false;
}
}
} return true;
}


下一步开始写dfs函数,
第一个参数是mp数组,是这一副棋盘,
第二个参数是n,代表的是棋盘的大小,
第三个参数是i,把2维的矩阵转换为1维了,例如i=1就对应着(0,1)这个点,以此类推。
第四个参数是queen,用来存现在放的棋子的个数。
public void dfs(char[][] mp, int len, int i,int queen) {
int x = i / len;
int y = i % len; if ((x >= len || y >= len)) {
if(queen!=len) return;
List<String> list = new ArrayList<>();
for (int a = 0; a < len; a++) {
String tmp = "";
for (int b = 0; b < len; b++) {
tmp += mp[a][b];
}
list.add(tmp);
}
ans.add(list);
return;
}
dfs(mp,len,i+1,queen);
if (ok(mp, len, x, y)) {
mp[x][y] = 'Q';
dfs(mp, len, i + 1,queen+1);
mp[x][y] = '.';
} }

整合一下,最后的AC代码为:

class Solution {
List<List<String>> ans = new ArrayList<>(); public List<List<String>> solveNQueens(int n) { char mp[][] = new char[n][n];
for (int i = 0; i < n; i++) {
for (int j = 0; j < n; j++) {
mp[i][j] = '.';
}
}
dfs(mp, n, 0,0); return ans;
} public void dfs(char[][] mp, int len, int i,int queen) {
int x = i / len;
int y = i % len; if ((x >= len || y >= len)) {
if(queen!=len) return;
List<String> list = new ArrayList<>();
for (int a = 0; a < len; a++) {
String tmp = "";
for (int b = 0; b < len; b++) {
tmp += mp[a][b];
}
list.add(tmp);
}
ans.add(list);
return;
}
dfs(mp,len,i+1,queen);
if (ok(mp, len, x, y)) {
mp[x][y] = 'Q';
dfs(mp, len, i + 1,queen+1);
mp[x][y] = '.';
} } public boolean ok(char[][] mp, int len, int x, int y) {
// check row
for (int i = 0; i < len; i++) {
if (i == y)
continue;
if (mp[x][i] == 'Q')
return false;
} // check col
for (int i = 0; i < len; i++) {
if (i == x)
continue;
if (mp[i][y] == 'Q')
return false;
} // x=1 y=3
int cnt = 0;
int up = 0;
int down = 0; for(int i=y+1;i<len;i++){
up = (++cnt)*-1+x;
down = cnt*1+x; if(up<len && up>=0){
//System.out.println("mp[up][i]=["+up+"]["+i+"]");
if(mp[up][i]=='Q')
return false;
} if(down>=0 && down<len){
//System.out.println("mp[down][i]=["+down+"]["+i+"]");
if(mp[down][i]=='Q'){
return false;
}
}
} //System.out.println("other");
cnt = 0;
for(int i=y-1;i>=0;i--){
up = (++cnt)*-1+x;
down = cnt*1+x; if(up<len && up>=0){
//System.out.println("mp[up][i]=["+up+"]["+i+"]");
if(mp[up][i]=='Q')
return false;
} if(down>=0 && down<len){
//System.out.println("mp[down][i]=["+down+"]["+i+"]");
if(mp[down][i]=='Q'){
return false;
}
}
} return true;
} }

Leetcode之回溯法专题-51. N皇后(N-Queens)的更多相关文章

  1. Leetcode之回溯法专题-52. N皇后 II(N-Queens II)

    Leetcode之回溯法专题-52. N皇后 II(N-Queens II) 与51题的代码80%一样,只不过52要求解的数量,51求具体解,点击进入51 class Solution { int a ...

  2. Leetcode之回溯法专题-216. 组合总和 III(Combination Sum III)

    Leetcode之回溯法专题-216. 组合总和 III(Combination Sum III) 同类题目: Leetcode之回溯法专题-39. 组合总数(Combination Sum) Lee ...

  3. Leetcode之回溯法专题-212. 单词搜索 II(Word Search II)

    Leetcode之回溯法专题-212. 单词搜索 II(Word Search II) 给定一个二维网格 board 和一个字典中的单词列表 words,找出所有同时在二维网格和字典中出现的单词. 单 ...

  4. Leetcode之回溯法专题-131. 分割回文串(Palindrome Partitioning)

    Leetcode之回溯法专题-131. 分割回文串(Palindrome Partitioning) 给定一个字符串 s,将 s 分割成一些子串,使每个子串都是回文串. 返回 s 所有可能的分割方案. ...

  5. Leetcode之回溯法专题-90. 子集 II(Subsets II)

    Leetcode之回溯法专题-90. 子集 II(Subsets II) 给定一个可能包含重复元素的整数数组 nums,返回该数组所有可能的子集(幂集). 说明:解集不能包含重复的子集. 示例: 输入 ...

  6. Leetcode之回溯法专题-79. 单词搜索(Word Search)

    Leetcode之回溯法专题-79. 单词搜索(Word Search) 给定一个二维网格和一个单词,找出该单词是否存在于网格中. 单词必须按照字母顺序,通过相邻的单元格内的字母构成,其中“相邻”单元 ...

  7. Leetcode之回溯法专题-78. 子集(Subsets)

    Leetcode之回溯法专题-78. 子集(Subsets) 给定一组不含重复元素的整数数组 nums,返回该数组所有可能的子集(幂集). 说明:解集不能包含重复的子集. 示例: 输入: nums = ...

  8. Leetcode之回溯法专题-77. 组合(Combinations)

    Leetcode之回溯法专题-77. 组合(Combinations)   给定两个整数 n 和 k,返回 1 ... n 中所有可能的 k 个数的组合. 示例: 输入: n = 4, k = 2 输 ...

  9. Leetcode之回溯法专题-47. 全排列 II(Permutations II)

    Leetcode之回溯法专题-47. 全排列 II(Permutations II) 给定一个可包含重复数字的序列,返回所有不重复的全排列. 示例: 输入: [1,1,2] 输出: [ [1,1,2] ...

随机推荐

  1. windows上node开发注意事项

    windows上进行node.react开发的必要步骤: 1.使用nvm进行node及npm包管理工具,记得使用npm config set ...:2.另外react仅支持python3.0以下的版 ...

  2. ubuntu环境下测试cache大小并校验

    Cache存储器:电脑中为高速缓冲存储器,是位于CPU和主存储器DRAM(Dynamic Random Access Memory)之间,规模较小,但速度很高的存储器,通常由SRAM(Static R ...

  3. markdown常用方法

    Markdown格式的普及流行要归功于Github和StackOverflow的流行,随着它们越来越流行,它们支持的Markdown格式也越来越流行. 1.优点 1.Markdown通过内容和样式相分 ...

  4. python交互界面无法使用方向键

    问题 python交互界面无法使用方向键,按方向键全变成^[[^C这类型的字符 解决办法 办法1: 使用yum安装readline.readline-devel,然后重装python 这种方法太麻烦了 ...

  5. S2:ArrayList

    1.ArrayList   ArrayList非常类似于数组,也有人称它为数组列表,ArrayList可以动态维护. 因为数组的长度是固定的,而SArrayList的容量可以根据需要自动扩充. Arr ...

  6. 对vue中nextTick()的理解及使用场景说明

    异步更新队列: 首先我们要对vue的数据更新有一定理解: vue是依靠数据驱动视图更新的,该更新的过程是异步的. 即:当侦听到你的数据发生变化时, Vue将开启一个队列(该队列被Vue官方称为异步更新 ...

  7. NLP(十四)自制序列标注平台

    背景介绍   在平时的NLP任务中,我们经常用到命名实体识别(NER),常用的识别实体类型为人名.地名.组织机构名,但是我们往往也会有识别其它实体的需求,比如时间.品牌名等.在利用算法做实体识别的时候 ...

  8. gdb调试和编译后运行结果不一致

    今天在看代码时,遇到这么一段代码,我但是用g++编译了,运行发现有Segmentation fault. 然后就用gdb跟进去看看,可是gdb却正常执行了.不知道什么原因. #include < ...

  9. 缓存的有效期和淘汰策略【Redis和其他缓存】【刘新宇】

    缓存有效期与淘汰策略 有效期 TTL (Time to live) 设置有效期的作用: 节省空间 做到数据弱一致性,有效期失效后,可以保证数据的一致性 Redis的过期策略 过期策略通常有以下三种: ...

  10. java学习-NIO(一)简介

    I/O简介 在 Java 编程中,直到最近一直使用 流 的方式完成 I/O.所有 I/O 都被视为单个的字节的移动,通过一个称为 Stream 的对象一次移动一个字节.流 I/O 用于与外部世界接触. ...