回溯(DFS)算法解题套路框架 :: labuladong的算法小抄 #1013
Replies: 89 comments 16 replies
-
合法了就做选择,做下一层决策,省了一个continue语句 ,这样好不好 for (int col = 0; col < n; col++) {
// 选择合法位置
if (isValid(board, row, col)) {
// 做选择
board[row][col] = 'Q';
// 进入下一行决策
backtrack(board, row + 1);
// 撤销选择
board[row][col] = '.';
}
} |
Beta Was this translation helpful? Give feedback.
-
@tinyhare 一样的 |
Beta Was this translation helpful? Give feedback.
-
意思是一样的 |
Beta Was this translation helpful? Give feedback.
-
请问N皇后问题,[".Q...","...Q.","Q....","....Q","..Q.."]满不满足条件 |
Beta Was this translation helpful? Give feedback.
-
continue的写法更好,guard clauses |
Beta Was this translation helpful? Give feedback.
-
东哥东哥,res.add(new LinkedList(track)); 改成res.add(track);怎么就不对了呢 |
Beta Was this translation helpful? Give feedback.
-
@xiangyueerli 因为这个 |
Beta Was this translation helpful? Give feedback.
-
妙啊 |
Beta Was this translation helpful? Give feedback.
-
N皇后有java版本嘛 |
Beta Was this translation helpful? Give feedback.
-
【Java版】不过我可能写得有点麻烦了,都是用的笨办法操作字符串😄 class Solution {
List<List<String>> res = new ArrayList<>();
public List<List<String>> solveNQueens(int n) {
ArrayList<String> board = new ArrayList<>();
StringBuilder sb = new StringBuilder();
for(int i = 0; i < n; i++){
sb.append('.');
}
for(int i = 0; i < n; i++){
board.add(sb.toString());
}
backtrack(board, 0);
return res;
}
private void backtrack(ArrayList<String> board, int row){
if(row == board.size()){
res.add(new ArrayList<>(board));
return;
}
int n = board.get(row).length();
for(int col = 0; col < n; col++){
if(!isValid(board, row, col)){
continue;
}
String r = board.remove(row);
StringBuilder sb = new StringBuilder(r);
sb.replace(col, col+1, "Q");
board.add(row, sb.toString());
backtrack(board, row+1);
r = board.remove(row);
sb = new StringBuilder(r);
sb.replace(col, col+1, ".");
board.add(row, sb.toString());
}
}
private boolean isValid(ArrayList<String> board, int row, int col){
int n = board.size();
for(int i = 0; i < n; i++){
String r = board.get(i);
if(r.charAt(col) == 'Q'){
return false;
}
}
for(int i = row - 1, j = col + 1; i >= 0 && j < n; i--,j++){
String r = board.get(i);
if(r.charAt(j) == 'Q'){
return false;
}
}
for(int i = row - 1, j = col - 1; i >= 0 && j >= 0; i--, j--){
String r = board.get(i);
if(r.charAt(j) == 'Q'){
return false;
}
}
return true;
}
} |
Beta Was this translation helpful? Give feedback.
-
class Solution {
List<List<String>> res = new ArrayList<>();
/* 输入棋盘的边长n,返回所有合法的放置 */
public List<List<String>> solveNQueens(int n) {
// "." 表示空,"Q"表示皇后,初始化棋盘
char[][] board = new char[n][n];
for (char[] c : board) {
Arrays.fill(c, '.');
}
backtrack(board, 0);
return res;
}
public void backtrack(char[][] board, int row) {
// 每一行都成功放置了皇后,记录结果
if (row == board.length) {
res.add(charToList(board));
return;
}
int n = board[row].length;
// 在当前行的每一列都可能放置皇后
for (int col = 0; col < n; col++) {
// 排除可以相互攻击的格子
if (!isValid(board, row, col)) {
continue;
}
// 做选择
board[row][col] = 'Q';
// 进入下一行放皇后
backtrack(board, row + 1);
// 撤销选择
board[row][col] = '.';
}
}
/* 判断是否可以在 board[row][col] 放置皇后 */
public boolean isValid(char[][] board, int row, int col) {
int n = board.length;
// 检查列是否有皇后冲突
for (int i = 0; i < n; i++) {
if (board[i][col] == 'Q') {
return false;
}
}
// 检查右上方是否有皇后冲突
for (int i = row - 1, j = col + 1; i >=0 && j < n; i--, j++) {
if (board[i][j] == 'Q') {
return false;
}
}
// 检查左上方是否有皇后冲突
for (int i = row - 1, j = col - 1; i >= 0 && j >= 0; i--, j--) {
if (board[i][j] == 'Q') {
return false;
}
}
return true;
}
public List charToList(char[][] board) {
List<String> list = new ArrayList<>();
for (char[] c : board) {
list.add(String.copyValueOf(c));
}
return list;
}
} |
Beta Was this translation helpful? Give feedback.
-
js 版本,利用闭包,省去了很多中间变量。 /* 输入棋盘边长 n,返回所有合法的放置 */
function solveNQueens(n) {
// '.' 表示空,'Q' 表示皇后,初始化空棋盘。
const board = new Array(n).fill(0).map(() => new Array(n).fill("."));
const res = [];
backtrack(0);
return res;
function isValid(row, col) {
// 检查列是否有皇后互相冲突
for (let i = 0; i < n; i++) {
if (board[i][col] === "Q") return false;
}
// 检查右上方是否有皇后互相冲突
for (let i = row - 1, j = col + 1; i >= 0 && j < n; i--, j++) {
if (board[i][j] === "Q") return false;
}
// 检查左上方是否有皇后互相冲突
for (let i = row - 1, j = col - 1; i >= 0 && j >= 0; i--, j--) {
if (board[i][j] === "Q") return false;
}
return true;
}
// 路径:board 中小于 row 的那些行都已经成功放置了皇后
// 选择列表:第 row 行的所有列都是放置皇后的选择
// 结束条件:row 超过 board 的最后一行
function backtrack(row) {
// 触发结束条件;
if (row === board.length) {
res.push(board.map((row) => row.join("")));
return;
}
for (let col = 0; col < n; col++) {
// 排除不合法选择;
if (!isValid(row, col)) {
continue;
}
// 做选择;
board[row][col] = "Q";
// 进入下一行决策;
backtrack(row + 1);
// 撤销选择;
board[row][col] = ".";
}
}
}
console.log(solveNQueens(4)); |
Beta Was this translation helpful? Give feedback.
-
Python3版本 class Solution:
def solveNQueens(self, n: int) -> List[List[str]]:
result = []
board = []
for i in range(n):
board.append(['.'] * n)
def isValid(row, col):
# 检查列是否有皇后
for i in range(n):
if board[i][col] == 'Q':
return False
# 检查右上方是否有皇后
i = row - 1
j = col + 1
while i >= 0 and j < n:
if board[i][j] == 'Q':
return False
i -= 1
j += 1
# 检查左上方是否有皇后
i = row - 1
j = col - 1
while i >= 0 and j >= 0:
if board[i][j] == 'Q':
return False
i -= 1
j -= 1
return True
def backtrack(row):
# 超出左后一行
if row == n:
result.append([''.join(b) for b in board])
return
for col in range(n):
# 排除不合法选择
if not isValid(row, col):
continue
# 做选择
board[row][col] = 'Q'
# 进入下一秒决策
backtrack(row + 1)
# 撤销选择
board[row][col] = '.'
backtrack(0)
return result |
Beta Was this translation helpful? Give feedback.
-
左右斜和竖线都可以用数组记录是否已被占据,代码更简洁高效 class Solution {
public:
vector<vector<string>> res;
vector<vector<string>> solveNQueens(int n) {
/*左斜编号由board[n-1][0]->l[0],往右上依次记录每条斜线,右斜由[0][0]->[0]往下*/
vector<bool> colflag(n,false),ldiag(2*n-1,false),rdiag(2*n-1,false);
vector<string> board(n,string(n,'.'));
backtrack(board,n,0,colflag,ldiag,rdiag);
return res;
}
void backtrack(vector<string>& board,int n,int row,vector<bool>& colflag,vector<bool>&ldiag,vector<bool>&rdiag){
if(row==n){res.push_back(board);return;}
for(int col=0;col<n;col++){
if(colflag[col]||ldiag[n-1-row+col]||rdiag[row+col])continue;
board[row][col]='Q';
colflag[col]=ldiag[n-1-row+col]=rdiag[row+col]=true;
backtrack(board,n,row+1,colflag,ldiag,rdiag);
board[row][col]='.';
colflag[col]=ldiag[n-1-row+col]=rdiag[row+col]=false;
}
}
}; |
Beta Was this translation helpful? Give feedback.
-
东哥YYDS! |
Beta Was this translation helpful? Give feedback.
-
感谢大佬的backtrack框架! |
Beta Was this translation helpful? Give feedback.
-
二刷打卡 |
Beta Was this translation helpful? Give feedback.
-
打卡 看得太舒服了 |
Beta Was this translation helpful? Give feedback.
-
for (int i = row - 1; i >= 0; i--) {
if (board[i][col] == 'Q')
return false;
} |
Beta Was this translation helpful? Give feedback.
-
在检查 column 是否有冲突的时候,应该不需要 loop 到 row,到 row-1 就够了 # check the column
for i in range(row):
if board[i][col] == 'Q':
return False |
Beta Was this translation helpful? Give feedback.
-
回溯算法是在遍历「树枝」,DFS 算法是在遍历「节点」,总结的太好了 |
Beta Was this translation helpful? Give feedback.
-
牛逼,赞了 |
Beta Was this translation helpful? Give feedback.
-
可视化动画太赞了! |
Beta Was this translation helpful? Give feedback.
-
52、N皇后II Python版本打卡 class Solution:
def totalNQueens(self, n: int) -> int:
self.res=0
temp=[['.']*n for _ in range(n)]
self.backtrack(n,0,temp)
return self.res
def backtrack(self,n,row,temp):
#结束条件
if row==n:
self.res+=1
for col in range(n):
if not self.isValid(row,col,temp,n):
continue
temp[row][col]='Q'
self.backtrack(n,row+1,temp)
temp[row][col]='.'
def isValid(self,row,col,temp,n):
#判断上方是否有皇后出没
for r in range(row):
if temp[r][col]=='Q':
return False
#判断左上方是否有皇后出没
r1,c1=row-1,col-1
while r1>=0 and c1>=0:
if temp[r1][c1]=='Q':
return False
r1-=1
c1-=1
#判断右上方是否有皇后出没
r2,c2=row-1,col+1
while r2>=0 and c2<n:
if temp[r2][c2]=='Q':
return False
r2-=1
c2+=1
return True |
Beta Was this translation helpful? Give feedback.
-
判断列上边是否有皇后,感觉不需要小于n,小于当前层row就可以了,和不用判断左下右下一个原因 |
Beta Was this translation helpful? Give feedback.
-
请问一下大家,对于这个问题,有没有一个比较好记忆的理解: 这个回溯的时候,添加和去除是在for循环里面,但是前文中图算法中的环检测(course schedule)的题中,添加和去除是在for循环外面的。不是很理解,为什么一个在里面,一个在外面。单看每一种算法,我可以理解,但是为什么两个问题的处理方法不一样呢?谢谢大家! |
Beta Was this translation helpful? Give feedback.
-
这里直接小于row,第row行不用判断,对不对?因为就是要放到这一行的 |
Beta Was this translation helpful? Give feedback.
-
每次写backtracking没啥问题,但一问complexity就卡壳,尤其是变种题或者有直接数学方法求组合数的题 |
Beta Was this translation helpful? Give feedback.
-
邮件已收到,谢谢。
华南理工大学2015级控制理论与控制工程 徐将将 tel:13560349491(629491) 地址:华工(五三
|
Beta Was this translation helpful? Give feedback.
-
在 “全排列问题” 的 C++ 解题方案中,作者用的是 譬如对于下面的代码: std::vector<bool> a = { false, true, false };
auto b = a[0];
bool c = a[0]; 对于变量 当然就 LeetCode 而言,这样用并不会报错,但是仍然不推荐这样使用。如果想使用 |
Beta Was this translation helpful? Give feedback.
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
-
文章链接点这里:回溯(DFS)算法解题套路框架
评论礼仪 见这里,违者直接拉黑。
Beta Was this translation helpful? Give feedback.
All reactions