LeetCode51-N皇后

昨天的英语考试终于是考完了啊

为了这门考试

我可是什么都豁出去了啊

复习资料打印了一大堆

凡是能够得到的资料都打印了

具体见下图

昨天早上还特地6点半就爬起床了

为了就是多看课本一眼

昨天的考试果然也没辜负我的辛苦努力

呜呜呜,大家快夸我,快夸我

啊哈哈哈哈哈哈哈哈哈!!!


51-N皇后

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

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

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

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

示例:

输入: 4
输出: [
 [".Q..",  // 解法 1
  "...Q",
  "Q...",
  "..Q."],

 ["..Q.",  // 解法 2
  "Q...",
  "...Q",
  ".Q.."]
]
解释: 4 皇后问题存在两个不同的解法。

思路:

如果看过我之前写的文章的朋友,看到这一题心里肯定乐开了花,因为我之前就一直给大家灌输回溯法的吊炸天的好处,并且还总结了一篇关于回溯法求解的文章,具体如下:

程小新同学:LeetCode--回溯法心得​zhuanlan.zhihu.com

在这篇文章里我就特地给出了关于N皇后的例子,因为实在是太经典了,并且相应给出了其解法。这两题唯一不同的就是最后N皇后组合情况的表示形式不一样罢了,其他的过程基本上是一摸一样了。但在这里,我还是想针对这题好好讲讲回溯的思路,我们总是讲回溯回溯,那它的核心是什么呢?搞清楚了这个你才能很快很好的利用这个方法解题。我总结的核心就是:当前递归的值一定能够回到其对应的上一次递归操作的值,只有能将当前值改成上一次操作的值,才能继续遍历操作,其实这个思想有点像暴力搜索。这不过这个是剪枝了的暴力搜索,当你发现某一次递归操作中的值不符合条件的时候,后面的递归操作也就不必进行了,直接回溯到上一个值并修改上一个值,继续进行递归操作。说了这么多,可能有些人已经晕了,可以看看我画的这张图,方便大家理解。

最后再多嘴一句:回溯算法其实就是模拟我们大脑思考相应问题的主流套路,对所有情况组成的树进行剪枝操作。

代码如下:

class Solution:
    # 关于这一题,我在之前写的一篇文章回溯法里写到了相应的解法,只不过答案的表达方式不同
    # N皇后问题算是特别经典的回溯法求解问题了
    def solveNQueens(self, n):
        """
        :type n: int
        :rtype: List[List[str]]
        """
        # 如果输入的n值(也就是棋盘大小的维度)小于0,这就是没意义了
        if n <= 0:
            return []
        # 定义保存每种解法的列表集合
        final_queens = []

        # 核心的递归函数
        def back(n_queen_list=[], current_row=0, queen_pos=[]):
            """
            :param n_queen_list: [[str]]-->用来存放每种符合要求情况下的皇后安置情况
            :param current_row: [int, int]-->用来指定当前皇后安放的位置(假设)不一定是最后安置的情况
            :param queen_pos: [[int, int]]-->专门用来保存所有皇后的坐标,方便查重函数conflict()的比较
            :return: None
            """
            # 出口条件,如果最后一行的皇后放置好了,说明答案也出来了
            if len(n_queen_list) == n:
                # 因为题目要求最终每一行的位置都是用一串字符串表示,所以这里得转换
                answer_list = []
                for index in n_queen_list:
                    answer_list.append(''.join(index))
                final_queens.append(answer_list)
                return True

            # 这里其实是对于当前行current_row每一列遍历查找符合要求的皇后位置
            for queen_col in range(n):
                # 指定准备用来检测的皇后位置
                current_queen = [current_row, queen_col]
                # 如果指定的皇后位置与之前安置的皇后位置上没有冲突,说明可以进行下一步递归检测,否则继续查找
                if self.conflict(queen_pos, current_queen) is False:
                    new_queen = ['.']*n
                    new_queen[queen_col] = 'Q'
                    # 这儿主要是记得保存当前位置,方便回溯
                    back(n_queen_list+[new_queen], current_row + 1, queen_pos + [current_queen])

        back()
        return final_queens

    # 检测皇后之间的位置关系
    def conflict(self, queen_pos, current_queen):
        """
        :param queen_pos: [[]]-->指代当前皇后存放之前的所有皇后的集合
        :param current_queen: []-->指代当前皇后想要存放的位置
        :return:Flag: boolean-->指代当前位置的皇后是否与之前所有位置的皇后有冲突
        """
        # 此处的queen_length既是之前保存的queen_list集合的长度,也可以理解为当前current_queen皇后的行下标
        queen_length = len(queen_pos)
        if queen_length == 0:
            return False
        # 定义是否有位置冲突的标签
        Flag = False
        for index in range(queen_length):
            # queen_length - index主要是控制相邻两行的皇后不能处于对角线上,其他的就没要求
            if abs(current_queen[1] - queen_pos[index][1]) in (0, queen_length - index):
                Flag = True
                break
        return Flag


if __name__ == "__main__":
    n = 4
    queen_list = Solution().solveNQueens(n)
    print(queen_list)

执行效率属于中等吧,在50%左右。

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

学习的学习者

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值