【算法题解】没有重复项数字的全排列

545 阅读2分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第23天,点击查看活动详情

描述

给出一组数字,返回该组数字的所有排列

例如:
[1,2,3]的所有排列如下
[1,2,3],[1,3,2],[2,1,3],[2,3,1],[3,1,2], [3,2,1].
(以数字在数组中的位置靠前为优先级,按字典序排列输出。)

数据范围:数字个数0<n60<n≤6

要求:空间复杂度 O(n!)O(n!) ,时间复杂度 O(n!O(n!)

示例1

输入:

[1,2,3]

返回值:

[[1,2,3],[1,3,2],[2,1,3],[2,3,1],[3,1,2],[3,2,1]]

示例2

输入:

[1]

返回值:

[[1]]

题目的主要信息:

  • 给出一组数字,返回该组数字的所有排列
  • 数字无重复
  • 以数字在数组中的位置靠前为优先级,按字典序排列输出

方法一:递归

具体做法:

可以通过递归,每次递归对每个下标的元素与它后面每个元素交换位置成为一种排列的情况,当下标到了数组结尾即可认为一种排列加入答案中。当某一种交换的结果经过了所有递归,需要进行回溯,以保证每种情况都有。如下图所示:

1.gif

class Solution {
public:
    void recursion(vector<vector<int> > &res, vector<int> & num, int index){
        if(index == num.size() - 1) //分枝进入结尾,找到一种排列
            res.push_back(num);
        else{
            for(int i = index; i < num.size(); i++){ //遍历后续的元素
                swap(num[i], num[index]); //交换二者
                recursion(res, num, index + 1); //继续往后找
                swap(num[i], num[index]); //回溯
            }
        }
    }
    vector<vector<int> > permute(vector<int> &num) {
        sort(num.begin(), num.end()); //先按字典序排序
        vector<vector<int> > res;
        recursion(res, num, 0); // 递归获取
        return res;
    }
};

复杂度分析:

  • 时间复杂度:O(n!)O(n!),n个元素的数组进行全排列
  • 空间复杂度:O(n),递归栈深度为n,其中返回矩阵res属于必要空间,不属于额外空间

方法二:库函数

具体做法:

可以使用next_permutation函数获取该数组全排列,因为该函数每次是获取字典序下的下一个排列,因此要先对原数组进行排序,排成升序后才能调用函数。

class Solution {
public:
    vector<vector<int> > permute(vector<int> &num) {
        sort(num.begin(), num.end()); //先按字典序排序
        vector<vector<int> > res;
        do{
            res.push_back(num);
        }while(next_permutation(num.begin(), num.end())); //全排列函数
        return res;
    }
};

复杂度分析:

  • 时间复杂度:O(n!)O(n!),n个元素的数组进行全排列
  • 空间复杂度:O(1)O(1),返回矩阵res属于必要空间,不属于额外空间