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

数据结构与算法之递归: LeetCode 46. 全排列 (Typescript版)

全排列

  • https://leetcode.cn/problems/permutations/

描述

  • 给定一个不含重复数字的数组 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 中的所有整数 互不相同

算法实现

1 )回溯1: 基于数组

function permute(nums: number[]): number[][] {const res: number[][] = [];// 回溯函数const backtrack = (path: number[]) => {// 满足当前条件if(path.length === nums.length) {res.push(path);return;}// 遍历for(let i = 0; i < nums.length; i++) {if(path.includes(nums[i])) continue;backtrack(path.concat(nums[i]));}}backtrack([]);return res;
}
  • 时间复杂度:O(n*n!)
    • 假设输入数组的长度为 n
    • 遍历每个元素的时间复杂度为 O(n)
    • 对于每个元素,都会进行递归调,假设数组中有 n 个不同的元素
    • 那么对于每个元素,都会有 n-1 个可能的选择,然后对于每个选择,又会有 n-2 个可能的选择,以此类推
    • 因此,递归的时间复杂度可以表示为 O(n!)。
    • 在每一层递归中,都会进行一次包含操作(includes),其时间复杂度为 O(n)。
    • 综合考虑,这段代码的时间复杂度为 O(n * n!),其中 n 表示输入数组的长度。
    • 需要注意的是,这里的时间复杂度分析基于平均情况。
    • 在最坏情况下,全排列的数量是 n!,因此在最坏情况下,时间复杂度为 O(n * n!)
    • 注意: n的阶乘公式: n! = 1*2*3*...*(n-1)*n
  • 空间复杂度:O(n)
    • 递归,堆栈,不是常量,是线性增长的
    • 是递归的层数

2 )回溯2: 基于交换

function permute(nums: number[]): number[][] {const res: number[][] = [];const backtrack = function(start: number) {if (start === nums.length - 1) {res.push([...nums]);return;}for (let i: number = start; i < nums.length; i++) {[nums[i], nums[start]] = [nums[start], nums[i]]; // 交换backtrack(start + 1); // 下一个数[nums[i], nums[start]] = [nums[start], nums[i]]; // 交换撤销}}backtrack(0); // 从 0 开始return res;
};
  • 这个问题可以看作有 n 个排列成一行的空格,我们需要从左往右依此填入题目给定的 n 个数,每个数只能使用一次
  • 那么很直接的可以想到一种穷举的算法,即从左往右每一个位置都依此尝试填入一个数
  • 看能不能填完这 n 个空格,在程序中我们可以用「回溯法」来模拟这个过程
  • 时间复杂度:O(n*n!),其中 n 为序列的长度
  • 空间复杂度:O(n)

回溯算法、递归和深度优先遍历(DFS)之间存在密切的关系

  • 它们通常在算法中一起使用,因为回溯算法通常使用递归来实现,并且常常涉及到深度优先遍历的思想。

  • 回溯算法与递归

    • 回溯算法是一种渐进式寻找并构建问题解决方案的策略。
    • 在回溯算法中,通常通过递归的方式来尝试所有可能的情况。
    • 当找到一个可能的解决方案时,它会继续探索下去,如果发现不符合条件,就会回溯到上一个状态,尝试其他可能的情况。
    • 因此,回溯算法通常使用递归来实现,因为递归天然地适合于处理这种尝试所有可能情况的问题。
  • 回溯算法与深度优先遍历

    • 回溯算法通常使用深度优先遍历的思想。
    • 在回溯算法中,我们会尝试一条路走到底,直到无法再继续下去,然后回溯到上一个状态,尝试其他的可能性。
    • 这与深度优先遍历的思想是一致的,深度优先遍历也是尽可能深地搜索树的分支,直到无法再继续为止
    • 然后回溯到上一个节点,继续搜索其他分支
  • 因此,回溯算法通常使用递归来实现,并且其思想与深度优先遍历密切相关。

  • 在许多情况下,回溯算法可以被视为一种特殊的深度优先遍历。

http://www.lryc.cn/news/248246.html

相关文章:

  • SQL中 JOIN 的两种连接类型:内连接(自然连接、自连接、交叉连接)、外连接(左外连接、右外连接、全外连接)
  • 微信小程序记住密码,让登录解放双手
  • 国内划片机行业四大企业之博捷芯:技术驱动,领跑未来
  • 后端整合Swagger+Knife4j接口文档
  • k8s中批量处理Pod应用的Job和CronJob控制器介绍
  • UE5 范围内随机生成
  • 杂记 | 使用Docker安装并配置MongoDB以支持事务(单副本,并解决了证书文件错误的问题)
  • css三角,鼠标样式,溢出文字
  • 远程桌面访问MATLAB 2018B,提示License Manger Error -103,终极解决方案
  • Jmeter基础和概念
  • 【Linux 带宽限速】trickle,限制docker 上传速度
  • MindStudio学习记录三:推理应用开发 acl mindx sdk
  • 【RT-DETR改进】SIoU、GIoU、CIoU、DIoU、AlphaIoU等二十余种损失函数
  • 【Linux】EVIOCGBIT
  • 鸿蒙4.0开发笔记之ArkTS装饰器语法基础@Extend扩展组件样式与stateStyles多态样式(十一)
  • 5V摄像机镜头驱动IC GC6208,可用于摄像机,机器人等产品中可替代AN41908
  • PHP echo和print 语句
  • ThinkPHP6.1 多应用模式的一些事儿
  • redis-cluster集群模式
  • 带你用uniapp从零开发一个仿小米商场_10. 首页开发
  • 常使用的定时任务
  • 【人工智能Ⅰ】实验2:遗传算法
  • Hadoop集群升级(3.1.3 -> 3.2.4)
  • (一)基于高尔夫优化算法GOA求解无人机三维路径规划研究(MATLAB)
  • ESP32-Web-Server编程-建立第一个网页
  • csgo/steam游戏搬砖项目的五大认知误区
  • ASCII sorting
  • redis--高可用之持久化
  • 『VUE3 の 要点摘录』
  • Buzz库python代码示例