当前位置: 首页 > article >正文

【算法】回溯算法专题③ ——排列型回溯 python

目录

  • 前置
  • 小试牛刀
  • 回归经典
  • 举一反三
  • 总结


前置


【算法】回溯算法专题① ——子集型回溯 python
【算法】回溯算法专题② ——组合型回溯 + 剪枝 python


小试牛刀


全排列 https://leetcode.cn/problems/permutations/description/


给定一个不含重复数字的数组 nums ,返回其 所有可能的全排列 。你可以 按任意顺序 返回答案。

示例 1:

输入:nums = [1,2,3]
输出:[[1,2,3],[1,3,2],[2,1,3],[2,3,1],[3,1,2],[3,2,1]]

示例 2:

输入:nums = [0,1]
输出:[[0,1],[1,0]]
示例 3:

输入:nums = [1]
输出:[[1]]

提示:

1 <= nums.length <= 6
-10 <= nums[i] <= 10
nums 中的所有整数 互不相同

思路:

用一个vis标记数组:对已选的数字打上标记


题解:

class Solution:
    def permute(self, nums: List[int]) -> List[List[int]]:
        n = len(nums)
        path = []
        ans = []
        vis = [0] * (n + 1)

        def dfs(i):
            if i == n:
                ans.append(path.copy())
                return
            for j in range(n):
                if not vis[j]:
                    vis[j] = 1
                    path.append(nums[j])
                    dfs(i + 1)
                    path.pop()
                    vis[j] = 0 # 别忘了回溯时将vis打回0

        dfs(0)
        return ans

当然vis标记数组可以通过递归时传入一个set参数代替


题解2:

class Solution:
    def permute(self, nums: List[int]) -> List[List[int]]:
        n = len(nums)
        path = []
        ans = []

        def dfs(i, s): # s:set
            if i == n:
                ans.append(path.copy())
                return
            for x in s:
                path.append(x)
                dfs(i + 1, s - {x})
                path.pop()

        dfs(0, set(nums)) # 用集合可以 O(1)判断元素是否在里面
        return ans


回归经典


N皇后 https://leetcode.cn/problems/n-queens/description/

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

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


思路:

同一对角线不能有多个皇后
(可以通过计算行号加或减列号来判断)


在这里插入图片描述

题解code:

class Solution:
    def solveNQueens(self, n: int) -> List[List[str]]:
        ans = []
        col = [0] * n  # col:列
        vis = [0] * n  # vis:标记数组
        diag1 = [0] * (2 * n)
        diag2 = [0] * (2 * n)
        # 分别表示两个对角线

        def dfs(r):  # row:行
            if r == n:
                ans.append(["." * c + "Q" + "." * (n - 1 - c) for c in col])
                return
            for c in range(n):
                if not vis[c] and not diag1[r + c] and not diag2[r - c]:
                    col[r] = c
                    vis[c] = diag1[r + c] = diag2[r - c] = 1
                    dfs(r + 1)
                    vis[c] = diag1[r + c] = diag2[r - c] = 0

        dfs(0)
        return ans




举一反三


小小变化一下,可以在对角线上,但有前提: 行号至少相差3

受伤的皇后 https://www.lanqiao.cn/problems/552/learning/

在这里插入图片描述

思路:

主要问题在于判断相同对角线上行号之差
以(2, 2)为例:
【右对角线】 的点是 (1, 3),【左对角线】 的点是 (3, 3),
可以发现:
(2, 2)和 (1, 3)的横坐标之差的绝对值=纵坐标之差的绝对值
同样的(2, 2)和 (3, 3)亦是如此,
所以判断两点是否在同一对角线,
即判断这两点的横纵坐标绝对值之差是否相等


题解code:

col = [0] * n
vis = [0] * n
diag1 = [0] * 2 * n
diag2 = [0] * 2 * n

def check(x, y):
    if not vis[y] and not diag1[x + y] and not diag2[x - y]:
        for i in range(x):
            if abs(i - x) == abs(col[i] - y) and abs(x - i) < 3:
                return 0
        return 1
    return 0

def dfs(r):
    if r == n:
        global ans
        ans += 1
        return
    for c in range(n):
        if check(r, c):
            col[r] = c
            vis[c] = diag1[r + c] = diag2[r - c] = 1
            dfs(r + 1)
            col[r] = 0
            vis[c] = diag1[r + c] = diag2[r - c] = 0
            
n = int(input())
ans = 0
dfs(0)
print(ans)


总结


回溯法是一种通过尝试每一种可能性来找到所有解的算法。对于N皇后问题,特别是带有额外约束条件的问题(如本题中的皇后之间在同一条45度角斜线上至少相隔3行),回溯法是一个非常合适的选择。


END
如果有更多问题或需要进一步的帮助,可以在评论区留言讨论哦!
如果喜欢的话,请给博主点个关注 谢谢


http://www.kler.cn/a/530824.html

相关文章:

  • 优化代码性能:利用CPU缓存原理
  • C# 结构体介绍
  • 汽车自动驾驶AI
  • Java创建对象有几种方式?
  • 在ubuntu下一键安装 Open WebUI
  • Cmake学习笔记
  • [MRCTF2020]Ez_bypass1(md5绕过)
  • 04树 + 堆 + 优先队列 + 图(D1_树(D10_决策树))
  • Rust中的结构体(Struct):数据组织的基石
  • 蓝桥杯备考:高精度算法之除法
  • 基于构件的软件开发方法
  • LeetCode - #197 Swift 实现找出温度更高的日期
  • Rust枚举(Enum)完全指南:用类型安全表达多样性
  • 前端力扣刷题 | 6:hot100之 矩阵
  • linux下ollama更换模型路径
  • 【腾讯前端面试】纯css画图形
  • WebSocket 实时通信详解:原理、应用与实践
  • 即梦(Dreamina)技术浅析(四):生成对抗网络
  • Vue指令v-html
  • Windows程序设计12:获取磁盘分区信息
  • STM32_SD卡的SDIO通信_DMA读写
  • C语言基础系列【1】第一个C程序:Hello, World!
  • AI时代IT行业职业方向规划大纲
  • java异常处理——try catch finally
  • OpenAI 实战进阶教程 - 第六节: OpenAI 与爬虫集成实现任务自动化
  • UE Bridge混合材质工具