• LeetCode刷题(python版)——Topic51N 皇后


    一、题设

    按照国际象棋的规则,皇后可以攻击与之处在同一行或同一列或同一斜线上的棋子。

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

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

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

    二、基本思路

            N皇后这种类似的棋盘问题,回溯即可:

            首先我们先写回溯算法,回溯的模板如下:

            def backtracking(参数):
        if 终止条件: # 达到叶子节点
            收集数据
            return
        # 单层逻辑
        for i  in range(lens):#遍历数据集
            处理节点
            backtracking(参数)
            撤销处理节点的操作

            (1)于是我们先确定终止条件:当填入n个皇后了就是产生了一个结果,将它收集.故终止条件为:if 某一回溯参数 == n(皇后个数) . 则res.append(...) return 

            (2)第二步,我们要确定单层逻辑:起初我想的是两层循环遍历每一个数组,这样写时间复杂度就高了,而且可能回不了。于是最核心的一个思路出来了,就是用一个全局的数组去记录每行的皇后所在位置,比如说flag[i] = j ,就代表第i行的皇后在第j列,其他没有皇后的位置就是'.',也可以暂时标记为-1.有个这个思想,我们就不用循环行了,而且还可以把行数当作回溯算法的一个参数传进来,这样不仅解决了终止条件,还减少了循环趟数。由此,我们循环第i行(i为传入参数)的每列,通过isValid()函数判断当前的(i,j)位置是否可以填入;若可填入则修改全局数组的值标记皇后位置,然后进行回溯.回溯之后的撤销操作即将皇后位置抹去。

            (3)第三步是去写isValid()函数:我们先从[0,row)遍历之前的皇后,如果flag[i] == col(有已标记皇后和当前皇后在一列),或者flag[i] + (row - i) == col(有已标记皇后和当前皇后在主对角线),或者flag[i] - (row - i) == col(有已标记皇后和当前皇后在副对角线),在同一行不用判断,因为我只循环列即一行填一次。

            那么关键就在于主副对角线上的判断条件怎么写,元素在主副对角线上即为横纵坐标差之比为1(主对角线),为-1(副对角线),则有:

                           

              (figure1:主对角线关系)                                             (figure2:副对角线关系)

     于是就有:

    1. if flag[i] == col or flag[i] + (row-i) == col or flag[i] - (row - i) == col:
    2. return False

            (4)第四步就是将存储好的一个数字列表转化成字符串啦,在这里就是用generateString()这一函数实现的.就是将全局标记数组中-1值的位置转化为'.',有非-1值得地方转化为'Q'即可。这里要注意的是,我起初想直接这样赋值:

    1. for row in range(n):
    2. s = ""
    3. for j in range(n):
    4. if j == flag[row]:
    5. s += 'Q'
    6. else:
    7. s += '.'

            以上是没毛病的,但是我在看评论的时候我看到了另一种赋值的方法,即第一遍全部填'.',第二遍直接利用索引填'Q',即这样:

    1. for row in range(n):
    2. s = ""
    3. for j in range(n):
    4. s += '.'
    5. s[flag[row]] = 'Q'

             直接用索引就会产生报错, 故还是直接用第一种方法即可.python中的s = ""只是生成了一个可迭代的字符容器罢了,具体的大小也没有确定,所以在使用索引时就会报错;而不是像Java中的这条语句,开辟了一段固定大小的空间。故python写法的用第一种方法遍历判断即可。

    char[] eachRow = new char[n]

    三、代码实现

    1. def solveNQueens(self, n):
    2. res = [] # 用于记录最后结果
    3. # flag记录当前行的状态
    4. # flag[i] = j 表示第i行的皇后在j列
    5. flag = [-1 for _ in range(n)]
    6. # generateString函数用于结合flag中的皇后位置生成一个结果
    7. def generateString(n):
    8. current_res = []
    9. for row in range(n):
    10. s = ""
    11. for j in range(n):
    12. if j == flag[row]:
    13. s += 'Q'
    14. else:
    15. s += '.'
    16. current_res.append(s)
    17. return current_res
    18. # 判断当前(row,col)能否填入
    19. def isValid(row,col):
    20. current_res = True
    21. # 遍历前几行
    22. for i in range(row):
    23. if flag[i] == -1:
    24. continue
    25. if flag[i] == col or flag[i] + (row-i) == col or flag[i] - (row - i) == col:
    26. return False
    27. return current_res
    28. def backtracing(n,row):
    29. if row == n:
    30. res.append(generateString(n))
    31. return
    32. for col in range(n):# 循环每一列
    33. # 当前位置不合法
    34. if not isValid(row,col):
    35. continue
    36. # 合法,可填入
    37. flag[row] = col
    38. backtracing(n,row + 1)
    39. flag[row] = -1
    40. backtracing(n,0)
    41. return res

    四、效率总结

  • 相关阅读:
    Maven Plugins And SpringBoot Package (一)
    【HDFS】Router JMX中的几个与connection相关的metric
    服务器防漏扫
    Arcgis pro属性表字段计算生成随机数
    自动化运维——ansible (五十三) (02)
    如何删除重复文件?简单操作法方法盘点!
    【Java基础】泛型+反射+枚举+Lambda表达式 知识点总结
    基于深度神经网络的社交媒体用户级心理压力检测
    WeakHashMap 和 HashMap 的区别是什么,何时使用?
    LinkedList的使用(Java)
  • 原文地址:https://blog.csdn.net/weixin_54039182/article/details/127644059