[LeetCode ] Permutations

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].

Diffculty Medium

Similar Problems [LeetCode ] Next Permutation Medium [LeetCode ] Permutations II Medium [LeetCode ] Permutation Sequence Medium [LeetCode ] Combinations Medium

Analysis

方法1: 经典方法 DFS 的递归。对于包含n个元素的数组 [1...n], 先确定第一位置的元素,第一个位置有 n 种可能(每次把后面的元素和第一个元素交换), 第一次是第一个元素与自己交换, A[0], (A[1] .. A[n-1]) 得出一个排列 第二次是第二个元素与第一个元素交换,A[1], (A[0], A[2]... A[n-1]) 得出第二个排列 第三次是第三个元素与第一个元素交换,A[2], (A[0], A[1], A[3] ... A[n-1]) ... 然后求交换后的每个子排列的全排列。由于一个数列的总共有 n! 个排列,因此时间复杂度为 O(n!)

class Solution {
public:
    vector<vector<int>> permute(vector<int>& A) {
        if(A.empty()) return {{}};
        vector<vector<int>> result;
        permute(A, 0, result);
        return result;
    }
    void permute(vector<int>& A, int start, vector<vector<int>>& res){
        int n = (int)A.size();
        if(start == n){
            res.push_back(A);
            return;
        }
        for(int i = start; i < n; ++i){
            swap(A[start], A[i]);
            permute(A, start + 1, res);  // 注意:这里是 start + 1,而不是 i + 1
            swap(A[start], A[i]);
        }
    }
};

方法2:插入法

与 subset I的方法2很相近。以题中例子说明: 当只有1时候:[1] 当加入2以后:[2, 1], [1, 2] 即在1的前后都插入2 当加入3以后:[3, 2, 1], [2, 3, 1], [2, 1, 3], [3, 1, 2], [1, 3, 2], [1, 2, 3] 前3个permutation分别对应将3插入[2, 1]的0, 1, 2的位置。同理后3个为插入[1, 2]的。因此可以用逐个插入数字来构造所有permutations。

class Solution {
public:
    vector<vector<int> > permute(vector<int> &A) {
        int n = A.size();
        vector<vector<int>> result;
        if(A.empty()) return result;
        result.push_back(vector<int>(1, A[0]));

        for(int i = 1; i < n; i++) {
            int m = result.size();
            for(int j = 0; j < m; j++) {
                for(int k = 0; k < result[j].size(); k++) {
                    vector<int> per = result[j];
                    per.insert(per.begin() + k, A[i]);
                    result.push_back(per);
                }
                result[j].push_back(A[i]);
            }
        }
        return result;
    }
};

方法3:backtracking 法 和 combination/subset 不同,数字不同的排列顺序算作不同的 permutation。 所以我们需要用一个辅助数组来记录当前递归层时,哪些数字(第i个)已经在上层的递归使用过了。

class Solution {
public:
    vector<vector<int> > permute(vector<int> &A) {
        vector<vector<int>> result;
        if(A.empty()) return result;
        vector<bool> used(A.size(), false);
        vector<int> per;
        findPermutations(A, used, per, result);
        return result;
    }

    void findPermutations(vector<int> &A, vector<bool> &used, vector<int> &per, vector<vector<int>> &result) {
        if(per.size() == (int)A.size()) {
            result.push_back(per);
            return;
        }

        for(int i = 0; i < (int)A.size(); i++) {
            if(used[i]) continue;
            used[i] = true;
            per.push_back(A[i]);
            findPermutations(A, used, per, result);
            used[i] = false;
            per.pop_back();
        }
    }
};

方法4:原地删除,添加 把处理过的元素在原数组中删除,然后处理完后续的之后添加回来,需要借助临时数组。

class Solution {
public:
    vector<vector<int>> permute(vector<int>& nums) {
        vector<vector<int>> res;
        if(nums.size() == 0) return res;
        vector<int> path;
        Permute_DFS(nums, path, res);
        return res;
    }
    void Permute_DFS(vector<int> &nums, vector<int> &path, vector<vector<int>> &res){
        if(nums.size() == 0) {
            res.push_back(path);
            return;
        }
        for(int i = 0; i < nums.size(); i++) {
            path.push_back(nums[i]);
            nums.erase(nums.begin() + i);
            Permute_DFS(nums, path, res);
            nums.insert(nums.begin() + i, path.back());
            path.pop_back();
        }
    }
};

results matching ""

    No results matching ""