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])) continue
    tempList.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

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Pillow教程06:将图片中出现的黄色和红色,改成绿色

---------------Pillow教程集合--------------- Python项目18&#xff1a;使用Pillow模块&#xff0c;随机生成4位数的图片验证码 Python教程93&#xff1a;初识Pillow模块&#xff08;创建Image对象查看属性图片的保存与缩放&#xff09; Pillow教程02&#xff1a;图片的裁…

律甲法务OA平台:信鸥科技引领法律行业新篇章

随着信息技术的飞速发展&#xff0c;法律行业也迎来了数字化转型的重要时刻。在这个信息化、智能化的时代&#xff0c;如何运用科技手段提升法律服务的质量和效率&#xff0c;成为法律行业亟待解决的问题。信鸥科技&#xff0c;作为业界的佼佼者&#xff0c;凭借其深厚的技术积…

flask_Restful数据解析参数设置

add_argument 方法参数详解 add_argument方法可以指定这个字段的名字&#xff0c;这个字段的数据类 型等&#xff0c;验证错误提示信息等&#xff0c;具体如下&#xff1a; default&#xff1a;默认值&#xff0c;如果这个参数没有值&#xff0c;那么将使用这个参数 指定的默认…

CTR之Session行为序列建模用户兴趣:DSIN

在前面的文章中&#xff0c;DIN模型 在用户行为序列建模中引入注意力机制来强调加权与target item相关的行为&#xff0c;以实现动态的兴趣表征&#xff1b;而DIEN模型 则在DIN的基础上加入时间性信息&#xff0c;使用注意力机制的GRU来挖掘用户兴趣的演变。 而今天的这篇文章…

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写作工具输出高质量内容?

随着人工智能技术的不断发展&#xff0c;AI写作工具正逐渐成为现代写作者的得力助手。它们能够通过智能算法分析大量的数据&#xff0c;生成高质量的文章内容&#xff0c;极大地提高了写作效率。但是&#xff0c;如何正确地使用这些AI写作工具输出高质量的内容&#xff0c;仍然…

Windows Server服务器FTP服务的配置与管理

前不久我们遇到一个Hostease的客户进行服务器迁移&#xff0c;他需要在Windows Server 2019上设置FTP&#xff08;File Transfer Protocol&#xff09;服务以帮助他在服务器和客户端之间传输文件。本教程将指导您逐步完成设置FTP服务的过程&#xff0c;并附上详细的图文说明&am…

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

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

文献速递:基于SAM的医学图像分割--SAMUS:适应临床友好型和泛化的超声图像分割的Segment Anything模型

Title 题目 SAMUS: Adapting Segment Anything Model for Clinically-Friendly and Generalizable Ultrasound Image Segmentation SAMUS&#xff1a;适应临床友好型和泛化的超声图像分割的Segment Anything模型 01 文献速递介绍 医学图像分割是一项关键技术&#xff0c;用…

嵌入式开发——基础电路知识

1. 电路知识 1.1. 驱动能力 IC是数字逻辑芯片&#xff0c;其输出的是逻辑电平。逻辑电平0表示输出电压低于阈值电压&#xff0c;逻辑1表示输出电压高于阈值电压。负载则是被驱动的电路或元件&#xff0c;负载大小则指负载的电阻大小。 驱动能力主要表现在几个方面&#xff1…

jenkins权限分配

1.安装权限插件 Role-Based Strategy 2.创建用户 3.修改全局安全配置中的授权策略为Role-Based Strategy 4.进入Manage and Assign Roles创建Global roles和Item roles 4.进入Assign Roles给用户分配role

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

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

Springboot:Actuator监控

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 目录 一、Actuator介绍 二、集成步骤 三、重要端点介绍 1、/actuator 2、/actuator/env 3、/actuator/heapdump 4、/actuator/metrics 5、/actuator/shutdown 6、/l…

jsp指令和动作

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

Qt Design Studio各个组件怎么用?【长期更新】

写在前面&#xff1a;本文长期更新&#xff0c;建议点赞/收藏/关注~ 在Qt Design Studio中&#xff0c;组件类别有&#xff1a; 每一种&#xff0c;都有其特定的用途和适用场景&#xff1a; 1.My Components 使用时机&#xff1a;当你需要重用自定义的设计元素或者特殊功能…

Capture One 23 下载地址及安装教程

Capture One 23 安装教程 Capture One是一款专业的图像编辑和管理软件&#xff0c;由丹麦公司Phase One开发。它广泛应用于专业摄影师和摄影爱好者之间的图像后期处理和管理。 Capture One提供了强大的图像编辑工具和功能&#xff0c;用于调整曝光、对比度、色彩、白平衡、…

Java_17 两数之和

两数之和 给定一个整数数组 nums 和一个整数目标值 target&#xff0c;请你在该数组中找出 和为目标值 target 的那 两个 整数&#xff0c;并返回它们的数组下标。 你可以假设每种输入只会对应一个答案。但是&#xff0c;数组中同一个元素在答案里不能重复出现。 你可以按任…

VRAY渲染设置大神参数(建议收藏)

3dmax效果图云渲染平台——渲染100以3ds Max 2024、VR 6.2、CR 11.2等最新版本为基础&#xff0c;兼容fp、acescg等常用插件&#xff0c;同时LUT滤镜等参数也得到了同步支持。注册填邀请码【7788】可领30元礼包和免费渲染券哦~ 公用&#xff1a;输出大小&#xff1a;一般小图50…

无人不识又无人不迷糊的this

关于this this关键字是JavaScript中最复杂的机制之一。它是一个很特别的关键字&#xff0c;被自动定义在所有函数的作用域中。 为什么要用this 随着开发者的使用模式越来越复杂&#xff0c;显式传递上下文对象会让代码变得越来越混乱&#xff0c;使用this则不会这样。 比如下面…

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

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