Leetcode 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
算法思想:
采用回溯算法。如果使用for循环,当且仅当知道表格的长和宽度的时候。如果不知道,那么for循环无能为力。
采用回溯算法,重点在于如何遍历一个二维数组。之前使用回溯算法都是表示一个数字,当前使用回溯算法表示一行。剩下就是套模板。在此基础上,要进行合法性判断,即判断当前这个点放皇后是否可行。具体可执行代码如下。
代码实现:
class Solution:
def solveNQueens(self, n: int):
result = []
chessboard = [['.']*n for _ in range(n)]
row = 0
self.backtracing(row, n, chessboard, result)
return result
def backtracing(self, row, n, chessboard, result):
if row == n:
result.append(copy.deepcopy(["".join(chessboard[i]) for i in range(n)]))
return
for col in range(n):
if self.isValid(row, col, n, chessboard):
chessboard[row][col] = "Q"
self.backtracing(row+1, n, chessboard, result)
chessboard[row][col] = "."
def isValid(self, row, col, n, chessboard):
# 检查列的情况,为什么不用检查行?因为是刚加进来的,本行肯定没有Q
for i in range(row):
if chessboard[i][col] == "Q":
return False
# 检查45度角
i, j = row - 1, col - 1
while i >= 0 and j >= 0:
if chessboard[i][j] == "Q":
return False
i = i - 1
j = j - 1
# 检查135度角
i, j = row - 1, col + 1
while i >= 0 and j < n:
if chessboard[i][j] == "Q":
return False
i = i - 1
j = j + 1
return True
Leetcode 37 解数独
题目:
编写一个程序,通过填充空格来解决数独问题。
数独的解法需 遵循如下规则:
数字 1-9 在每一行只能出现一次。
数字 1-9 在每一列只能出现一次。
数字 1-9 在每一个以粗实线分隔的 3x3 宫内只能出现一次。(请参考示例图)
数独部分空格内已填入了数字,空白格用 ‘.’ 表示。
示例 1:
输入:
board =
[[“5”,“3”,“.”,“.”,“7”,“.”,“.”,“.”,“.”],
[“6”,“.”,“.”,“1”,“9”,“5”,“.”,“.”,“.”],
[“.”,“9”,“8”,“.”,“.”,“.”,“.”,“6”,“.”],
[“8”,“.”,“.”,“.”,“6”,“.”,“.”,“.”,“3”],
[“4”,“.”,“.”,“8”,“.”,“3”,“.”,“.”,“1”],
[“7”,“.”,“.”,“.”,“2”,“.”,“.”,“.”,“6”],
[“.”,“6”,“.”,“.”,“.”,“.”,“2”,“8”,“.”],
[“.”,“.”,“.”,“4”,“1”,“9”,“.”,“.”,“5”],
[“.”,“.”,“.”,“.”,“8”,“.”,“.”,“7”,“9”]]
输出:
[
[“5”,“3”,“4”,“6”,“7”,“8”,“9”,“1”,“2”],
[“6”,“7”,“2”,“1”,“9”,“5”,“3”,“4”,“8”],
[“1”,“9”,“8”,“3”,“4”,“2”,“5”,“6”,“7”],
[“8”,“5”,“9”,“7”,“6”,“1”,“4”,“2”,“3”],
[“4”,“2”,“6”,“8”,“5”,“3”,“7”,“9”,“1”],
[“7”,“1”,“3”,“9”,“2”,“4”,“8”,“5”,“6”],
[“9”,“6”,“1”,“5”,“3”,“7”,“2”,“8”,“4”],
[“2”,“8”,“7”,“4”,“1”,“9”,“6”,“3”,“5”],
[“3”,“4”,“5”,“2”,“8”,“6”,“1”,“7”,“9”]
]
解释:输入的数独如上图所示,唯一有效的解决方案如下所示:
提示:
- board.length ==9
- board[i].length == 9
- board[i][j] 是一位数字或者 ‘.’
- 题目数据 保证 输入数独仅有一个解
算法思想:
采用回溯算法。如果采用for循环,可想而知,要用多少for?所以采用另外一种暴力解法,回溯算法。
与之前方法不同的是,本题要使用双层for循环遍历。第一循环遍历行,第二个循环遍历列。
遍历逻辑是:
如果当前board[i][j] 是数字的话,continue,跳过;
如果当前board[i][j]是非数字,range(1, 10) 遍历,填空,此时要判断所填数字是否有效。
如果无效,continue;
如果有效,填入数字,下一层递归开始。
什么时候返回False?如果遍历完10个数字,都是有冲突的,返回False
什么时候返回True?当行和列都遍历结束,如果没有返回False,则返回True。
代码实现:
class Solution:
def solveSudoku(self, board) -> None:
"""
Do not return anything, modify board in-place instead.
"""
self.backtracing(board)
def backtracing(self, board):
for i in range(len(board)): # 遍历行
for j in range(len(board[0])): # 遍历列
if board[i][j] != ".":
continue
else:
for k in range(1, 10):
if self.is_valid(i, j, k, board):
board[i][j] = str(k)
res = self.backtracing(board)
if res == True:
return True
board[i][j] = "."
else:
continue
return False
return True
def is_valid(self, row, col, val, board):
'''
参数说明: 检查哪一行, 哪一列, 检查什么值, 在哪里检查
'''
val = str(val)
# 检查行
for i in range(9):
if board[row][i] == val:
return False
# 检查列
for j in range(9):
if board[j][col] == val:
return False
# 检查9公格
start_row = (row // 3) * 3
start_col = (col // 3) * 3
for i in range(start_row, start_row+3):
for j in range(start_col, start_col+3):
if board[i][j] == val:
return False
return True