07、JS实现:用回溯法实现数组全排列的算法(一步一步剖析,很详细)

回溯法实现数组全排列的算法

  • Ⅰ、回溯法实现数组全排列:
    • 1、题目描述:
    • 2、解题思路:
    • 3、实现代码:
  • Ⅱ、小结:

Ⅰ、回溯法实现数组全排列:

1、题目描述:

给定⼀个 没有重复 数字的序列,返回其所有可能的全排列。
示例:
输⼊: [1,2,3]
输出:
[
[1,2,3],
[1,3,2],
[2,1,3],
[2,3,1],
[3,1,2],
[3,2,1]
]

2、解题思路:

以 [1,2,3] 为例,根据回溯思想,我们的逻辑是:
先从 [1,2,3] 选取⼀个数。
然后继续从 [1,2,3] 选取⼀个数,并且这个数不能是已经选取过的数。
重复这个过程直到选取的数字个数达到了 3。


可能存在的问题:
其一、如何确保这个数不能是已经选取过的数?
答:我们可以直接在已经选取的数字中线性查找,也可以将已经选取的数字中放到 hashset 中,这样就可以在
O(1)的时间来判断是否已经被选取了,只不过需要额外的空间;

3、实现代码:

其一、代码为:


// 此时的 list 是空数组、tempList 是空数组、nums 是没有重复数字的数组;
const backtrack = (list, tempList, nums) => {if (tempList.length === nums.length) return list.push([...tempList])for (let i = 0; i < nums.length; i++) {// 此时 continue 的作用:若 if() 满足条件,则会跳出本次的 for 循环;if (tempList.includes(nums[i])) continuetempList.push(nums[i])backtrack(list, tempList, nums)tempList.pop()}
}const permute = (nums) => {const list = []backtrack(list, [], nums)return list
}// 此时的输出结果为:[ [ 1, 2, 3 ], [ 1, 3, 2 ], [ 2, 1, 3 ], [ 2, 3, 1 ], [ 3, 1, 2 ], [ 3, 2, 1 ] ];
permute([1, 2, 3])
执行  backtrack(list, [], nums)  函数后代码执行的过程(即:执行 backtrack([], [], [1,2,3]) 函数):注意:里面涉及多个循环嵌套递归,每次递归的出口为 tempList.length === nums.length,循环的出口为 for() 循环结束;第一层循环,在 i=0 的情况下:if (tempList.includes(nums[i])) continue 的判断不成功;执行 tempList.push(nums[0]) 代码后,tempList 数组为 [1];backtrack(list, tempList, nums) 执行代码为:backtrack([], [1], [1,2,3])第二层循环,在 i=0 的情况下:if (tempList.includes(nums[i])) continue 的判断成功,因此直接跳出此次的 for() 循环的过程;第二层循环,在 i=1 的情况下:if (tempList.includes(nums[i])) continue 的判断不成功;执行 tempList.push(nums[1]) 代码后,tempList 数组为 [1,2];backtrack(list, tempList, nums) 执行代码为:backtrack([], [1,2], [1,2,3])第三层循环,在 i=0 的情况下:if (tempList.includes(nums[i])) continue 的判断成功,因此直接跳出此次的 for() 循环的过程;第三层循环,在 i=1 的情况下:if (tempList.includes(nums[i])) continue 的判断成功,因此直接跳出此次的 for() 循环的过程;第三层循环,在 i=2 的情况下:if (tempList.includes(nums[i])) continue 的判断不成功;执行 tempList.push(nums[2]) 代码后,tempList 数组为 [1,2,3];backtrack(list, tempList, nums) 执行代码为:backtrack([], [1,2,3], [1,2,3])if (tempList.length === nums.length) return list.push([...tempList]),list 的数组为[[1,2,3]];执行 tempList.pop() 代码后,tempList 数组为 [1,2];执行 tempList.pop() 代码后,tempList 数组为 [1];第二层循环,在 i=2 的情况下:if (tempList.includes(nums[i])) continue 的判断不成功;执行 tempList.push(nums[2]) 代码后,tempList 数组为 [1,3];backtrack(list, tempList, nums) 执行代码为:backtrack([[1,2,3]], [1,3], [1,2,3])第三层循环,在 i=0 的情况下:if (tempList.includes(nums[i])) continue 的判断成功,因此直接跳出此次的 for() 循环的过程;第三层循环,在 i=1 的情况下:if (tempList.includes(nums[i])) continue 的判断不成功;执行 tempList.push(nums[1]) 代码后,tempList 数组为 [1,3,2];backtrack(list, tempList, nums) 执行代码为:backtrack([[1,2,3]], [1,3,2], [1,2,3])if (tempList.length === nums.length) return list.push([...tempList]),list 的数组为[[1,2,3],[1,3,2]];执行 tempList.pop() 代码后,tempList 数组为 [1,3];第三层循环,在 i=2 的情况下:if (tempList.includes(nums[i])) continue 的判断成功,因此直接跳出此次的 for() 循环的过程;			执行 tempList.pop() 代码后,tempList 数组为 [1];执行 tempList.pop() 代码后,tempList 数组为 [];第一层循环,在 i=1 的情况下:if (tempList.includes(nums[i])) continue 的判断不成功;执行 tempList.push(nums[1]) 代码后,tempList 数组为 [2];backtrack(list, tempList, nums) 执行代码为:backtrack([[1,2,3],[1,3,2]], [2], [1,2,3])第二层循环,在 i=0 的情况下:if (tempList.includes(nums[i])) continue 的判断不成功;执行 tempList.push(nums[0]) 代码后,tempList 数组为 [2,1];backtrack(list, tempList, nums) 执行代码为:backtrack([[1,2,3],[1,3,2]], [2,1], [1,2,3])第三层循环,在 i=0 的情况下:if (tempList.includes(nums[i])) continue 的判断成功,因此直接跳出此次的 for() 循环的过程;第三层循环,在 i=1 的情况下:if (tempList.includes(nums[i])) continue 的判断成功,因此直接跳出此次的 for() 循环的过程;第三层循环,在 i=2 的情况下:if (tempList.includes(nums[i])) continue 的判断不成功;执行 tempList.push(nums[2]) 代码后,tempList 数组为 [2,1,3];backtrack(list, tempList, nums) 执行代码为:backtrack([[1,2,3],[1,3,2]], [2,1,3], [1,2,3])if (tempList.length === nums.length) return list.push([...tempList]),list 的数组为[[1,2,3],[1,3,2],[2,1,3]];执行 tempList.pop() 代码后,tempList 数组为 [2,1];执行 tempList.pop() 代码后,tempList 数组为 [2];第二层循环,在 i=1 的情况下:if (tempList.includes(nums[i])) continue 的判断成功,因此直接跳出此次的 for() 循环的过程;第二层循环,在 i=2 的情况下:if (tempList.includes(nums[i])) continue 的判断不成功;执行 tempList.push(nums[2]) 代码后,tempList 数组为 [2,3];backtrack(list, tempList, nums) 执行代码为:backtrack([[1,2,3],[1,3,2],[2,1,3]], [2,3], [1,2,3])第三层循环,在 i=0 的情况下:if (tempList.includes(nums[i])) continue 的判断不成功;执行 tempList.push(nums[0]) 代码后,tempList 数组为 [2,3,1];backtrack(list, tempList, nums) 执行代码为:backtrack([[1,2,3],[1,3,2],[2,1,3]], [2,3,1], [1,2,3])if (tempList.length === nums.length) return list.push([...tempList]),list 的数组为[[1,2,3],[1,3,2],[2,1,3],[2,3,1]];执行 tempList.pop() 代码后,tempList 数组为 [2,3];第三层循环,在 i=1 的情况下:if (tempList.includes(nums[i])) continue 的判断成功,因此直接跳出此次的 for() 循环的过程;第三层循环,在 i=2 的情况下:if (tempList.includes(nums[i])) continue 的判断成功,因此直接跳出此次的 for() 循环的过程;			执行 tempList.pop() 代码后,tempList 数组为 [2];执行 tempList.pop() 代码后,tempList 数组为 [];第一层循环,在 i=2 的情况下:if (tempList.includes(nums[i])) continue 的判断不成功;执行 tempList.push(nums[2]) 代码后,tempList 数组为 [3];backtrack(list, tempList, nums) 执行代码为:backtrack([[1,2,3],[1,3,2],[2,1,3],[2,3,1]], [3], [1,2,3])第二层循环,在 i=0 的情况下:if (tempList.includes(nums[i])) continue 的判断不成功;执行 tempList.push(nums[0]) 代码后,tempList 数组为 [3,1];backtrack(list, tempList, nums) 执行代码为:backtrack([[1,2,3],[1,3,2],[2,1,3],[2,3,1]], [3,1], [1,2,3])第三层循环,在 i=0 的情况下:if (tempList.includes(nums[i])) continue 的判断成功,因此直接跳出此次的 for() 循环的过程;第三层循环,在 i=1 的情况下:if (tempList.includes(nums[i])) continue 的判断不成功;执行 tempList.push(nums[1]) 代码后,tempList 数组为 [3,1,2];backtrack(list, tempList, nums) 执行代码为:backtrack([[1,2,3],[1,3,2],[2,1,3],[2,3,1]], [3,1,2], [1,2,3])if (tempList.length === nums.length) return list.push([...tempList]),list 的数组为[[1,2,3],[1,3,2],[2,1,3],[2,3,1],[3,1,2]];执行 tempList.pop() 代码后,tempList 数组为 [3,1];第三层循环,在 i=2 的情况下:if (tempList.includes(nums[i])) continue 的判断成功,因此直接跳出此次的 for() 循环的过程;执行 tempList.pop() 代码后,tempList 数组为 [3];第二层循环,在 i=1 的情况下:if (tempList.includes(nums[i])) continue 的判断不成功;执行 tempList.push(nums[1]) 代码后,tempList 数组为 [3,2];backtrack(list, tempList, nums) 执行代码为:backtrack([[1,2,3],[1,3,2],[2,1,3],[2,3,1],[3,1,2]], [3,2], [1,2,3])第三层循环,在 i=0 的情况下:if (tempList.includes(nums[i])) continue 的判断不成功;执行 tempList.push(nums[0]) 代码后,tempList 数组为 [3,2,1];backtrack(list, tempList, nums) 执行代码为:backtrack([[1,2,3],[1,3,2],[2,1,3],[2,3,1],[3,1,2]], [3,2,1], [1,2,3])if (tempList.length === nums.length) return list.push([...tempList]),list 的数组为[[1,2,3],[1,3,2],[2,1,3],[2,3,1],[3,1,2],[3,2,1]];执行 tempList.pop() 代码后,tempList 数组为 [3,2];第三层循环,在 i=1 的情况下:if (tempList.includes(nums[i])) continue 的判断成功,因此直接跳出此次的 for() 循环的过程;第三层循环,在 i=2 的情况下:if (tempList.includes(nums[i])) continue 的判断成功,因此直接跳出此次的 for() 循环的过程;			执行 tempList.pop() 代码后,tempList 数组为 [3];第二层循环,在 i=2 的情况下:if (tempList.includes(nums[i])) continue 的判断成功,因此直接跳出此次的 for() 循环的过程;执行 tempList.pop() 代码后,tempList 数组为 [];因此,最后 list 的输出结果为:[ [ 1, 2, 3 ], [ 1, 3, 2 ], [ 2, 1, 3 ], [ 2, 3, 1 ], [ 3, 1, 2 ], [ 3, 2, 1 ] ],
而 tempList 的输出结果为:[];

其二、截图为:

在这里插入图片描述

Ⅱ、小结:

其一、哪里有不对或不合适的地方,还请大佬们多多指点和交流!
其二、若有转发或引用本文章内容,请注明本博客地址(直接点击下面 url 跳转) https://blog.csdn.net/weixin_43405300,创作不易,且行且珍惜!
其三、有兴趣的话,可以多多关注这个专栏(Vue(Vue2+Vue3)面试必备专栏)(直接点击下面 url 跳转):https://blog.csdn.net/weixin_43405300/category_11525646.html?spm=1001.2014.3001.5482

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/571627.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

2024刚做抖店,对接主播/达人的全过程,专为新手准备的教程

内容来源于【醒醒团队-电商王路飞】 第一步&#xff1a;开通精选联盟 想找主播给你带货的话&#xff0c;精选联盟是必须要开通的&#xff0c;你们之间的合作、链接的上下架等等也需要通过精选联盟去完成。 这一点&#xff0c;我在之前分享的抖音小店基础搭建内容里&#xff…

如何使用CHAT-AI?

伴随着CHAT-GPT的出现&#xff0c;人们都喜欢上了CHAT-AI。嗯&#xff1f;你还不会用&#xff1f;&#xff01; 教程来喽&#xff01; 首先点这里的 … 点击扩展 接着选择“管理扩展” 点击之后搜索“wetab” 最后你需要注册一个号&#xff0c;然后就可以使用CHAT-AI啦&#x…

JavaScript混淆工具选择与使用指南

摘要 本文介绍了什么是js混淆工具&#xff0c;以及为什么需要使用js混淆工具。详细解释了js混淆工具的实现原理和作用&#xff0c;探讨了如何选择合适的js混淆工具&#xff0c;列举了几款常用的js混淆工具&#xff0c;并对它们的特点和适用场景进行了分析。最后总结了js混淆工…

2024年第16届大广赛新命题发布-爱华仕箱包

2024年3月27日&#xff0c;2024年第16届大广赛发布了新的命题&#xff0c;爱华仕箱包命题&#xff0c;自2017年起&#xff0c;爱华仕箱包已连续8年担任全国大学生广告艺术大赛命题单位。 爱华仕现已实现百货、超市、电商、礼品、投标、海外市场6大零售网络的全覆盖&#xff0c…

第十三届蓝桥杯省赛C++ A组 Java A组/研究生组《推导部分和》(C++)

【题目描述】 【输入格式】 【输出格式】 【数据范围】 【输入样例】 5 3 3 1 5 15 4 5 9 2 3 5 1 5 1 3 1 2 【输出样例】 15 6 UNKNOWN 【思路】 题解来源&#xff1a;AcWing 4651. $\Huge\color{gold}{推导部分和}$ - AcWing 【代码】 #include<bits/stdc.h> #define…

工业无线网关在汽车制造企业的应用效果和价值-天拓四方

随着智能制造的快速发展&#xff0c;工业无线网关作为关键通信设备&#xff0c;在提升生产效率、优化生产流程、实现设备间的互联互通等方面发挥着越来越重要的作用。以下是一个关于工业无线网关在智能制造行业应用的具体案例&#xff0c;展示了其在实际生产中的应用效果和价值…

jsp指令和动作

1.page指令&#xff1a;描述页面信息 pageENcoding:软件编码 contentType&#xff1a;浏览器编码 2.include指令&#xff1a;将多个网页合成一个网页&#xff0c;静态包含网页 问题&#xff1a;1.在网页源代码中&#xff0c;会形成错误的多遍代码&#xff0c;将主页面代码和…

2024游泳耳机哪个牌子好?分析测评四大热门游泳耳机

随着科技的不断发展&#xff0c;游泳耳机已经成为游泳爱好者们在水中畅游时的最佳伴侣。近年来游泳耳机市场涌现出了众多品牌和产品&#xff0c;让人眼花缭乱。为了帮助大家挑选到最适合自己的游泳耳机&#xff0c;我们特意对市面上四大热门游泳耳机进行了详细的分析测评&#…

labelme自动标注工具的安装和python代码修改

labelme嵌入SAM和EfficientSAM自动标注模型 目录: 1.labelme windows环境下安装python版本labelme 2.labelme.exe直接安装 3.labelme生成exe 4.labelme python代码修改 labelme自动标注使用方法 编辑/Create AI-Polygon 自动分割,直接生成分割图,标注为point,完成标注后…

AI智能分析网关V4使用GB28181注册到EasyCVR平台的具体步骤

旭帆科技的智能分析网关V4内含近40种智能分析算法&#xff0c;包括人体、车辆、消防、环境卫生、异常检测等等&#xff0c;在消防安全、生产安全、行为检测等场景应用十分广泛。如常见的智慧工地、智慧校园、智慧景区、智慧城管等等&#xff0c;还支持抓拍、记录、告警、语音对…

html2canvas 请求阿里云oss图片跨域问题解决

1. html2canvas设置 useCORS:true html2canvas(this.$refs.qrcode, {useCORS:true,}).then(canvas > {// 转成图片&#xff0c;生成图片地址let oImg new Image()oImg canvas.toDataURL(image/png) // 导出图片var oA document.createElement("a")oA.download…

推特社交机器人分类

机器人有不同的种类。 cresci-17数据集中的三种不同的机器人类:传统垃圾机器人、社交垃圾机器人和假追随者。 传统的垃圾邮件机器人会生成大量推广产品的内容&#xff0c;并且可以通过频繁使用的形容词来检测; 社交垃圾邮件倾向于攻击或支持政治候选人&#xff0c;因此情绪是一…