Codelet Keep code simple stupid

Permutations

Question

Given a collection of distinct numbers, return all possible permutations.

For example, [1,2,3] have the following permutations:

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

其实一直都不怎么会排列组合的算法,今天好好研究了一番,现在做一下记录

Solution

  • 思路:首元素交换+递归
#include <vector>
#include <utility>
using namespace std;

class Solution {
public:
  vector<vector<int>> permute(vector<int>& nums) {
    vector<vector<int>> result;
    if (nums.size() == 1) {
      result.push_back(nums);
      return result;
    }
    for (int i = 0; i < nums.size(); i++) {
      swap(nums[0], nums[i]);
      int head = nums[0];
      vector<int> sub(nums.begin() + 1, nums.end());
      vector<vector<int>> tmp = permute(sub);
      for (int j = 0; j < tmp.size(); j++) {
        vector<int>& ref = tmp[j];
        ref.insert(ref.begin(), head);
        result.push_back(ref);
      }
      swap(nums[0], nums[i]);
    }
    return result;
  }
};
  • 第一种解法很直观,但是中间涉及了临时向量的开辟与首元素插入,产生了不必要的开销; 而且递归的返回值是vector,我用的是笛卡儿积(Cartesian product)的形式追加结果,应该还可以 继续优化

    下面是解法二:引用结果+直接修改 拷贝追加

#include <vector>
#include <utility>
using namespace std;

typedef vector<int> VecInt;

class Solution {
public:
  vector<vector<int>> permute(vector<int>& nums) {
    vector<vector<int>> result;
    permuteHelper(result, nums, 0, nums.size());
    return result;
  }

  void permuteHelper(vector<VecInt>& result,
                     VecInt& nums,
                     int begin,
                     int end) {
    if (end - begin == 1) { // length 1
      result.push_back(nums);
    }
    for (int i = begin; i < end; i++) {
      swap(nums[begin], nums[i]);
      permuteHelper(result, nums, begin + 1, end);
      swap(nums[begin], nums[i]);
    }
  }
};
  • 其实C++的STL已经提供了排列算法next_permutation(不太明白为什么要提供这个库函数, 不常用啊),不过前提要求升序排列,有额外的开销
#include <vector>
#include <algorithm>
using namespace std;

class Solution {
public:
  vector<vector<int>> permute(vector<int>& nums) {
    vector<vector<int>> result;
    sort(nums.begin(), nums.end());
    result.push_back(nums);
    while (next_permutation(nums.begin(), nums.end())) {
      result.push_back(nums);
    }
    return result;
  }
};