Loading [MathJax]/jax/output/CommonHTML/config.js
部署DeepSeek模型,进群交流最in玩法!
立即加群
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >LeetCode46 回溯算法求全排列,这次是真全排列

LeetCode46 回溯算法求全排列,这次是真全排列

作者头像
TechFlow-承志
发布于 2020-04-14 13:53:48
发布于 2020-04-14 13:53:48
68800
代码可运行
举报
文章被收录于专栏:TechFlowTechFlow
运行总次数:0
代码可运行

在之前的文章当中,我们讲过八皇后、回溯法,也提到了全排列,但是毕竟没有真正写过。今天的LeetCode46题正是让我们生成给定元素的全排列。

题意很简单,只有一句话,给定一个没有重复元素的序列,让我们返回这个序列所有的全排列,并且我们不需要考虑这些排列的顺序。

回溯法

我们在之前的文章当中分析过,全排列问题,可以看成是搜索问题,从而近似成八皇后问题。在八皇后问题当中,我们枚举的是棋盘的每一行当中的皇后放置的位置,而全排列其实也一样,我们要枚举每一个元素放置的位置。不过八皇后当中要求皇后除了不能同行同列之外还不能同对角线,而我们排列元素可以忽略这个要求。也就是说我们把每一行皇后放置的列号看成是每个元素摆放的位置,并且忽略同对角线的限制的话,那么八皇后问题和全排列问题就完全一样了。

如果还不理解,可以参考一下下图,我们给皇后编号,把皇后同样看成是序列当中的元素,那么八皇后的摆放位置刚好可以映射成一种排列。映射的方式非常简单,就是我们忽略行的信息,依次记录下皇后摆放的列号。

如果你能想通这两个看似完全不同的问题当中的相似之处,说明你对搜索问题的理解已经有些入门了。

思路清楚了,总之我们要枚举皇后摆放的状态。你可以按顺序遍历位置,然后枚举各个位置上放置的皇后,也可以顺序遍历皇后,枚举当前皇后可以放置的位置。两者是等价的,你可以根据自己的理解进行操作。

一般来说我喜欢遍历位置,枚举皇后。因为会引起冲突的是皇后,而不是位置。我们往往要判断皇后之间的关系以及皇后的状态,所以我们枚举皇后会比较贴合思路

所以我们把之前八皇后的代码拿过来稍作修改即可,为了放置一个皇后重复放置在多个位置,我们需要存储皇后的状态,即有没有放置过。一般竞赛当中这种标记的变量称为flag,如果标记多个那就是flag数组。更多细节我们来看代码:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
class Solution:
    def dfs(self, nums, n, i, cur, ret, flag):
        if i == n:
            ret.append(cur.copy())
            return
        for p in range(n):
            # 遍历所有元素
            # 如果p元素已经放置过了,跳过
            if flag[p]:
                continue
            # 当前位置放置p
            cur.append(nums[p])
            # flag[p]置为True
            flag[p] = True
            # 递归
            self.dfs(nums, n, i+1, cur, ret, flag)
            # 回溯
            cur.pop()
            flag[p] = False
        
    def permute(self, nums: List[int]) -> List[List[int]]:
        ret = []
        n = len(nums)
        # 记录元素i有没有放置过
        flag = [False for _ in range(n)]
        self.dfs(nums, n, 0, [], ret, flag)
        return ret

代码很短,细节也不多,只要理解了我们是按照顺序遍历位置,然后对于每一个位置遍历可以放置的元素,然后递归回溯即可。基本上可以说是模板题,如果理解有难度的话,可以看一下之前详解八皇后问题的文章:

LeetCode 31:递归、回溯、八皇后、全排列一篇文章全讲清楚

其他方法

回溯法是这个问题的标准解法,那么这题还有没有其他方法呢?

其实是有的,也不难,在LeetCode31题的文章,也就是上面那个链接的文章当中我们解决了一个叫做下一个排列的问题。在这道题当中,我们给定一个序列,要求返回在它所有的全排列当中刚好字典序比它大1的排列,这个方法称为next_permutation。

关于next_permutation的计算方法也在链接里,如果有忘记的或者是最近关注的可以点下链接回顾一下,计算方法是完全一样的,我就不再重复了,链接和上面的是一样的,上面看过了这里就不用点了。

LeetCode 31:递归、回溯、八皇后、全排列一篇文章全讲清楚

如果还记得这道题的话就好办了,我们使用它很容易解出当前的问题。因为我们只需要获得给定序列的最小排列,然后不停地调用这个方法就好了,直到没有更大的序列退出即可。从最小的序列一直获取到最大的,当然就是全排列了。

在LeetCode31题当中,这是一个inplace的方法,没有返回值。并且当序列达到最大的时候,会自动再从最小的开始。我们需要稍稍修改一下,加上一个返回值,表示当前的序列是否是最大的。如果序列达到最大,说明我们可以不用继续往下寻找了,我们return一个True,表示可以退出了,否则我们return False,表示还有其他结果。

本质上我们是从最小的排列开始,不停地用一个叫做get_next的方法获取比当前序列大的下一个序列,当没有更大的序列的时候,说明我们已经获得了所有的排列,那么直接返回结果即可。如果忽略get_next当中的逻辑,这个代码其实只有几行:

其实这是一个取巧的办法,利用之前的思路我们完全不用思考,几乎可以无脑得到答案。但是从另外一个角度来说,这也是算法的魅力,毕竟通往终点的路往往不止一条。

最后我们来看下代码,如果你不懂怎么算next_permutation光看注释是很难看懂的,划到上面的链接看看吧。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
class Solution:
    def get_next(self, nums: List[int]):
        """
        Do not return anything, modify nums in-place instead.
        """
        # 长度
        n = len(nums)
        # 记录图中i-1的位置
        pos = n - 1
        for i in range(n-1, 0, -1):
            # 如果降序破坏,说明找到了i
            if nums[i] > nums[i-1]:
                pos = i-1
                break
                
        for i in range(n-1, pos, -1):
            # 从最后开始找大于pos位置的
            if nums[i] > nums[pos]:
                # 先交换元素,在进行翻转
                nums[i], nums[pos] = nums[pos], nums[i]
                # 翻转[pos+1, n]区间
                nums[pos+1:] = nums[n:pos:-1]
                return False
        return True
        
        
    def permute(self, nums: List[int]) -> List[List[int]]:
        ret = []
        # 从小到大排序,获得最小排列
        nums = sorted(nums)
        ret.append(nums.copy())
        # 如果还有下一个排列则继续调用
        while not self.get_next(nums):
            # 要.copy()是因为Python中存储的引用,如果不加copy
            # 会导致当nums发生变化之后,ret中存储的数据也会变化
            ret.append(nums.copy())
        return ret

今天的问题并不难,只是Medium难度,并且题目的题意还是之前见过的,主要是给大家加深一下回溯算法的印象用的,没什么太多的新内容。

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2020-04-04,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 Coder梁 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
暂无评论
推荐阅读
编辑精选文章
换一批
mpvue1.0+python3.7+Django2.0.4实现微信小程序的支付功能
    其实微信支付有很多种形式,刷脸,扫码,APP支付,小程序支付等,这边只说明小程序支付的实现,不过原理上都大同小异。
用户9127725
2022/08/08
5910
mpvue1.0+python3.7+Django2.0.4实现微信小程序的支付功能
CMDB学习之六 --客户端请求测试,服
客户端使用agent 请求测试,agent使用的POST 请求,使用requests模块
py3study
2020/02/10
5520
CMDB之数据采集
利用saltstack的salt.client模块可以在python的命令行下或者python脚本里执行相应的salt命令
超蛋lhy
2018/08/31
1.8K0
CMDB之数据采集
python requests
Request支持HTTP连接保持和连接池,支持使用cookie保持会话,支持文件上传,支持自动响应内容的编码,支持国际化的URL和POST数据自动编码。
forxtz
2022/05/10
1.7K0
小朋友学Python Web(2):Get和Post请求
如果你要做一个App项目,比如iOS或安卓项目,这时App和后端的项目是分离的。 此时要发网络请求,可以采用Get方式,也可以采用Post方式。 这里先介绍Get方式。 新建client_get.py,模拟客户端的GET请求 client_get.py中的完整代码为
海天一树
2018/10/08
8180
小朋友学Python Web(2):Get和Post请求
python3+django2 开发易语言网络验证(中)
第四步:网络验证的逻辑开发 1.将model注册到adminx.py中 1.在apps/yanzheng目录下新建admin.py 文件,添加代码: import xadmin from xadmin import views from .models import Cards class BaseSetting(object): """ 引入更换主题功能 """ enable_themes = True use_bootswatch = True class
玩蛇的胖纸
2018/06/08
5.9K0
Python 接口测试requests.post方法中data与json参数区别
  在随笔分类Jmeter入门基础中,分享过一篇《Jmeter处理http请求Content-Type类型和传参方式》,这篇文章主要讲述Jmeter做接口测试时,针对POST请求参数的传递方式。而在使用requests做接口测试的时候,与之不太一样。requests.post主要参数是data与json,这两者使用是有区别的,下面我详情的介绍一下使用方法。
全栈测试开发日记
2023/02/02
1K0
Django 获取请求参数
  我们在使用python做接口测试的时候,通常使用的是requests库。而大家都知道还有一个request东西,很多人对requests与request两个东西傻傻分不清。下面我简单来介绍一下。
全栈测试开发日记
2023/02/02
2.9K0
Django 获取请求参数
python模块之requests及应用
Python标准库中提供了:urllib、urllib2、httplib等模块以供Http请求,但是,它的 API 太渣了。它是为另一个时代、另一个互联网所创建的。它需要巨量的工作,甚至包括各种方法覆盖,来完成最简单的任务。
菲宇
2019/06/12
1.6K0
python模块之requests及应用
Django框架学习(一)
1、POST/PUT/DELETE/PATCH访问一个url地址的时候才可以带请求体
小闫同学啊
2019/07/18
2.3K0
Django框架学习(一)
Django REST framework+Vue 打造生鲜超市(六) 七、用户登录与手机注册
七、用户登录与手机注册 7.1.drf的token (1)INSTALL_APP中添加 INSTALLED_APPS = ( ... 'rest_framework.authtoken
zhang_derek
2018/04/16
6.1K2
Django REST framework+Vue 打造生鲜超市(六)
		七、用户登录与手机注册
Python—requests模块详解
Request支持HTTP连接保持和连接池,支持使用cookie保持会话,支持文件上传,支持自动响应内容的编码,支持国际化的URL和POST数据自动编码。
forxtz
2020/10/10
3.1K0
python3 django整理(九) django 接收参数,以json彼此传递post与get
HTTP没有要求,如果Method是POST数据就要放在BODY中。也没有要求,如果Method是GET,数据(参数)就一定要放在URL中而不能放在BODY中。
学到老
2019/01/25
3.8K0
python3 django整理(九)  django 接收参数,以json彼此传递post与get
使用Django2.0.4集成钉钉第三方扫码登录
    钉钉作为阿里旗下的一款免费移动通讯软件,受众群体越来越多,这里我们使用Django来集成一下钉钉的三方账号登录,首先注册钉钉开发平台:https://open-dev.dingtalk.com/
用户9127725
2022/08/08
6420
使用Django2.0.4集成钉钉第三方扫码登录
RESTful API
网络应用程序,分为前端和后端两个部分。当前的发展趋势,就是前端设备层出不穷(手机、平板、桌面电脑、其他专用设备......)。
用户1214487
2022/03/26
1.7K0
RESTful API
使用 Python 的 requests 库发送 POST 请求(data vs json 参数详解)
在使用 Python 进行 Web 开发时,经常需要通过 HTTP 请求与服务器进行数据交换。requests 是一个流行的 Python 库,用于发送 HTTP 请求。在使用 requests.post() 方法时,我们经常会遇到 data 和 json 两个参数,它们在传递数据时有着不同的用途和行为。本教程将详细介绍这两个参数的区别,并且通过实例演示如何在 Django Rest Framework 中处理这些数据。
IT蜗壳-Tango
2024/08/07
5.6K0
Django入门
Django是一个高级的Python Web框架,它支持快速开发和简洁实用的设计。这篇文章是看了Django官方文档并进行练习之后总结的笔记,主要总结入门需要了解的几个知识点:
玖柒的小窝
2021/10/06
1.5K0
Django入门
爬虫小白:03.requests的使用
安装:pip install requests 导包:import requests
见贤思齊
2020/08/05
1.3K0
requests+BeautifulSoup详解
简介 Python标准库中提供了:urllib、urllib2、httplib等模块以供Http请求,但是,它的 API 太渣了。它是为另一个时代、另一个互联网所创建的。它需要巨量的工作,甚至包括各种方法覆盖,来完成最简单的任务。 Requests 是使用 Apache2 Licensed 许可证的 基于Python开发的HTTP 库,其在Python内置模块的基础上进行了高度的封装,从而使得Pythoner进行网络请求时,变得美好了许多,使用Requests可以轻而易举的完成浏览器可有的任何操作。 请求的
人生不如戏
2018/07/05
1.6K0
python requests模块
使用requests可以模拟浏览器的请求,比起之前用到的urllib,requests模块的api更加便捷(本质就是封装了urllib3)
用户5760343
2019/07/27
1.4K0
相关推荐
mpvue1.0+python3.7+Django2.0.4实现微信小程序的支付功能
更多 >
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档
本文部分代码块支持一键运行,欢迎体验
本文部分代码块支持一键运行,欢迎体验