首页 > 编程语言 >【算法】如何获取一个数组的全排列?

【算法】如何获取一个数组的全排列?

时间:2023-09-17 17:24:02浏览次数:37  
标签:... arr start 交换 获取 算法 result 数组

问题描述

给定一个任意数组,如何获得数组的全排列,例如[1,2,3]的全排列数组为[[1,2,3],[1,3,2],[2,1,3],[2,3,1],[3,2,1],[3,1,2]],即包含所有排列结果的长度为 \(A_{n}^{n}\) 的数组。

算法

function permute(arr) {
    const result = [];
    perm(arr, 0, result);
    return result;
}

function perm(arr, start, result) {
    if (start === arr.length) {
        result.push([...arr]);
    }
    for (let i = start; i < arr.length; i++) {
        [arr[start], arr[i]] = [arr[i], arr[start]];
        perm(arr, start + 1, result);
        [arr[start], arr[i]] = [arr[i], arr[start]];
    }
}
代码展开
// arr=[1,2,3];start=0;result=[]
function perm(arr, start, result) {
    if (start === arr.length) {
        result.push([...arr]);
    }
    for (let i = start; i < arr.length; i++) {
        // i=0时;start=0
        [arr[0], arr[0]] = [arr[0], arr[0]];
        // perm(arr, start + 1, result);
        // arr=[1,2,3];start=1;result=[]
        for (let i=1;i<3;i++) {
            // i=1时
            [arr[1], arr[1]] = [arr[1], arr[1]];
            // perm(arr, start + 1, result);
            // arr=[1,2,3];start=2;result=[];
            for (let i=2;i<3;i++){
                // i只能为2
                [arr[2], arr[2]] = [arr[2], arr[2]];
                // perm(arr, start + 1, result);
                // arr=[1,2,3];start=3;result=[];
                result.push([...[1,2,3]]); // arr=[1,2,3];start=3;result=[[1,2,3]];
                [arr[2], arr[2]] = [arr[2], arr[2]];
            }
            [arr[1], arr[1]] = [arr[1], arr[1]]; // arr=[1,2,3];start=2;result=[[1,2,3]];

            // i=2时
            [arr[1], arr[2]] = [arr[2], arr[1]]; // arr=[1,3,2]
            // perm(arr, start + 1, result);
            // arr=[1,3,2];start=2;result=[[1,2,3]];
            for (let i=2;i<3;i++){
                // i只能为2,重复执行
                result.push([...[1,3,2]]); // result=[[1,3,2];start=3;result=[[1,2,3],[1,3,2]];
            }
            [arr[1], arr[2]] = [arr[2], arr[1]]; // arr=[1,2,3];start=2;result=[[1,2,3],[1,3,2]];
        }
        [arr[0], arr[0]] = [arr[0], arr[0]]; // arr=[1,2,3];start=1;result=[[1,2,3],[1,3,2]];

        // i=1时;start=0;
        [arr[0], arr[1]] = [arr[1], arr[0]]; // arr=[2,1,3]
        // perm(arr, start + 1, result);
        // arr=[2,1,3];start=1;result=[[1,2,3],[1,3,2]];
        for (let i=1;i<3;i++) {
            // i=1时
            [arr[1], arr[1]] = [arr[1], arr[1]];
            // perm(arr, start + 1, result);
            // arr=[2,1,3];start=2;result=[[1,2,3],[1,3,2]];
            for(let i=2;i<3;i++){
                // i只能为2
                [arr[2], arr[2]] = [arr[2], arr[2]];
                // perm(arr, start + 1, result);
                // arr=[2,1,3];start=3;result=[[1,2,3],[1,3,2]];
                result.push([...[2,1,3]]); // arr=[2,1,3];start=3;result=[[1,2,3],[1,3,2],[2,1,3]];
                [arr[2], arr[2]] = [arr[2], arr[2]];
            }
            [arr[1], arr[1]] = [arr[1], arr[1]];

            // i=2时
            [arr[1], arr[2]] = [arr[2], arr[1]]; // arr=[2,3,1]
            // perm(arr, start + 1, result);
            // arr=[2,3,1];start=2;result=[[1,2,3],[1,3,2],[2,1,3]];
            for (let i=2;i<3;i++){
                //i只能为2
                // perm(arr, start + 1, result);
                // result = [[1,2,3],[1,3,2],[2,1,3],[2,3,1]];
            }
            [arr[1], arr[2]] = [arr[2], arr[1]]; // arr=[2,1,3]
        }
        [arr[0], arr[1]] = [arr[1], arr[0]]; // arr=[1,2,3]
        // 执行完后result=[[1,2,3],[1,3,2],[2,1,3],[2,3,1]];

        // i=2时;start=0
        [arr[0], arr[2]] = [arr[2], arr[0]]; // arr=[3,2,1]
        // ...
        // 执行完后result=[[1,2,3],[1,3,2],[2,1,3],[2,3,1],[3,2,1],[3,1,2]];
    }
}
解释

现在总共有n个数,从1n,即arr=[1,2,3,...,n-1,n],交换流程如下:

  1. 数1开始交换,先和自己交换,数组不变,但要等数2、数3、...、数n-1、数n交换完成,自己才算交换完成。一直推到最后一个数身上,最后一个数和自己交换,数组不变。全排列数组增加原数组arr为第一个元素。结果长度为1!
  2. 前面数的交换依赖后面数的交换,此时看数n-1,数n-1和数n交换,得到新item=[1,2,...,n-2,n,n-1],本轮数n-1交换完成。结果长度为2!
  3. 数n-2开始交换,依次和n-1、n交换,和n-1交换后,n-1的还有自己的交换,即[n-1,n-2,n]、[n-1,n,n-2]、[n,n-1,n-2]、[n,n-2,n-1],实际是后3个数的全排列,去掉已经出现的结果,所以结果长度为3!
  4. 依次类推,数i交换后结果长度为(n-i+1)!。一直到数2交换完后,结果长度为(n-1)!,至此,数1后面每个数的交换都完成,说明数1和自己的交换完成。
  5. 数1和自己的交换完成后,数1和数2交换,新数组执行同样的流程,数2、数3、...、数n-1、数n依次执行交换。每轮结果长度增加(n-1)!
  6. 数1和数3、...、数n交换,最后结果总长度为n*(n-1)!=n!

标签:...,arr,start,交换,获取,算法,result,数组
From: https://www.cnblogs.com/lhjc/p/17709222.html

相关文章

  • JavaScript 创建并初始化任意长度的数组
    直接定义vararr=[0,0,0,0,0];//[0,0,0,0,0]使用push()方法vararr=[];for(leti=0;i<5;i++){arr.push(0);}//[0,0,0,0,0]使用Array构造函数和fill()方法vararr=newArray(5);//[empty×5]arr.fill(0);//[0......
  • JS计算数组层级(深度)
    如果有一个多层嵌套的数组,想要计算其层级(深度),可以使用递归或迭代方法来实现。以下是两种常用的方法示例:递归方法:functioncalculateDepth(arr){if(!Array.isArray(arr)){return0;//如果不是数组,返回0表示不是层级结构}letmaxDepth=0;for(const......
  • linux获取文件或者是进程精确时间的方法
    linux获取文件或者是进程精确时间的方法背景很多时候需要精确知道文件的具体时间.也需要知道进程的开始的精确时间.便于进行一些计算的处理.其实linux里面有很多方式进行文件属性的查看.这里简单总结一下.文件系统时间查看ls以及ll命令可以查看文件的一些简......
  • [8]-代码随想录算法训练营-day9-字符串-part2
    代码随想录算法训练营第九天|字符串-part21.Leecode28.找出字符串中第一个匹配项的下标题目https://leetcode.cn/problems/find-the-index-of-the-first-occurrence-in-a-string/思路暴力for循环刷随想录后想法KMP模式匹配算法实现困难KMP算法理解......
  • [7]-代码随想录算法训练营-day8-字符串-part1
    代码随想录算法训练营第八天|数组字符串-part11.Leecode344.反转字符串题目https://leetcode.cn/problems/reverse-string/思路刷随想录后想法双指针,用swap实现困难无实现代码classSolution{public:voidreverseString(vector<char>&s){......
  • 【LeetCode】删除数对后的最小数组长度
    题目给你一个下标从0开始的非递减整数数组nums。你可以执行以下操作任意次:选择两个下标i和j,满足i<j且nums[i]<nums[j]。将nums中下标在i和j处的元素删除。剩余元素按照原来的顺序组成新的数组,下标也重新从0开始编号。请你返回一个整数,表示执行......
  • 【配色优化】基于遗传算法进行图形着色优化附matlab代码
    ✅作者简介:热爱科研的Matlab仿真开发者,修心和技术同步精进,matlab项目合作可私信。......
  • 数组(三)
    数组排序算法今日份学习为数组的排序算法。数组的排序算法分为三种:冒泡排序,直接选择排序以及反转排序。冒泡排序冒泡排序法在先前的C语言学习中已经有过接触。它的基本思想是对比相邻的元素值,如果满足条件就交换元素值,把较小的元素移动到数组面前,把较大的元素移动到数组后面。【......
  • C语言之[数组]篇
    前言牛牛又和大家见面了,本篇牛牛要讲的内容是c语言中有关数组的内容。欢迎大家一起学习,共同进步。@TOC数组通过前面所学到的知识,我们了解到,当我们需要使用一些变量的时候,我们可以通过创建变量来使用它,但是,有的时候我们需要使用很多个同类型的变量,那样一个个创建是否显得太过繁琐?......
  • 计算机视觉算法中的人体动作识别(Human Action Recognition)
    引言人类的动作是一种非常重要的信息来源,它能传达出人们的意图、情感和行为。因此,对于计算机来说,能够准确识别和理解人体动作是一项具有挑战性的任务。计算机视觉领域中的人体动作识别(HumanActionRecognition)旨在从图像或视频中自动识别和解释人体的运动模式和行为。本文将介绍人......