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进行全排列。在对2、3进行全排列的过程中呢,我们采取的方法也是一样的,就是固定住2,对3进行全排列。(由此可以看出这里可以用递归)固定住1的全排列排完之后呢,我们就要开始固定2的全排列了。直至固定完每一位数实现全部的排列组合。

3、代码实现

void perm(int pos, vector<int> &num, vector<vector<int>> &all_result) {
    if (pos + 1 == num.size()) {
        // 一次全排列的结果
        all_result.push_back(num);
        return;
    }
    for (int i = pos; i < num.size(); ++i) {
        swap(num[pos], num[i]); //先固定一个值
        perm(pos+1, num, all_result); //对剩下的进行全排列
        swap(num[pos], num[i]); //要恢复序列的原始序列
    }
}
int main() {
    vector<int> num = {1, 2, 3};
    vector<vector<int>> all_result; //存放全排列结果的容器
    perm(0, num, all_result);
}

4、算法复杂度

  • 时间复杂度:O(N*N!),全排列的时间复杂度为N!,每次排列结果需要遍历一次nums数组。
  • 空间复杂度:O(1)。

5、STL中的全排列

以上是我们自己写的全排列,但是STL中也给我们提供了全排列函数:std::next_permutation(first, last)。 例子:

#include <algorithm>
#include <string>
#include <iostream>

int main()
{
    std::string s = "aba";
    std::sort(s.begin(), s.end());
    do {
        std::cout << s << '\n';
    } while(std::next_permutation(s.begin(), s.end()));
}
/*
output:
aab
aba
baa
*/

5、运用场景

我们只要根本题目本身加上相应的逻辑即可。(比如上面两道全排列题目)

很多时候使用全排列尝尝因为时间复杂度太高而AC不了。这是因为很多排列不是符合我们题中条件的排列,我们可以利用一些技巧来优化一下。