Leetcode 刷题第30天 | 51,37

本文介绍了使用回溯算法解决LeetCode中的n皇后问题和数独问题的方法。n皇后问题涉及在棋盘上放置皇后以避免互相攻击,而数独则是通过填充数字满足行、列和3x3宫格规则。文章详细展示了如何用回溯法遍历并判断棋盘位置的有效性。
摘要由CSDN通过智能技术生成

Leetcode 51 N皇后问题

问题:

按照国际象棋的规则,皇后可以攻击与之处在同一行或同一列或同一斜线上的棋子。
n 皇后问题 研究的是如何将 n 个皇后放置在 n×n 的棋盘上,并且使皇后彼此之间不能相互攻击。
给你一个整数 n ,返回所有不同的 n 皇后问题 的解决方案。
每一种解法包含一个不同的 n 皇后问题 的棋子放置方案,该方案中 ‘Q’ 和 ‘.’ 分别代表了皇后和空位。
示例 1:
示例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:
示例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”]
]
解释:输入的数独如上图所示,唯一有效的解决方案如下所示:
示例1-1
提示:

  • 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
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值