1. 程式人生 > >演算法總結(9)--全排列問題

演算法總結(9)--全排列問題

leetcode上涉及到的全排列,注意陣列的有序,無序,陣列元素是否有重複的
主要是遞迴演算法
每個問題記住關鍵點,注意特殊處理


1。 全排列就是從第一個數字起每個數分別與它後面的數字交換

2。 去重的全排列就是從第一個數字起每個數分別與它後面非重複出現的數字交換

3。 求下一序列 4個步驟

  1. 從後往前找到第一個不是遞增的數字的位置,記錄下為p,如果p已經走到盡頭,那麼直接顛倒所有數字然後返回

  2. 從p往後找到比p大的最小的那個數的位置q(第一個比p位置大的)

  3. 交換p,q的位置

  4. 對於p之後(不包括p)的所有數 逆序

46. Permutations(全排列)

題目地址

ac程式碼要記牢

陣列數字不重複,最基礎的遞迴, 直接敲出來

class Solution {
private:
    vector<vector<int>> ans;

public:

    void recursion(int k,vector<int> nums, int n)
    {
        if (k >= n)
            return;
        if (k == n - 1){
        /*  for (int i = 0; i < n; i++)     
                cout << nums[i] << " ";
            cout << endl;*/
ans.push_back(nums); } for (int i = k; i < n; i++) { swap(nums[k], nums[i]); recursion(k + 1, nums, n); swap(nums[k], nums[i]); } } vector<vector<int>> permute(vector<int>& nums) { // nums是distinct
int n = nums.size(); if (n == 0) return ans; recursion(0, nums, n); return ans; } };

47. Permutations II(全排列去重)

題目地址

求解思路

去重:可以採用排序判斷,set集合等,或者自己寫個方法判重
總之記住上面去重的方法

31. Next Permutation(下一序列)

題目地址

ac程式碼

class Solution {
public:

    void rev(vector<int> &nums, int left, int right){
        for (int i = left; i <= (left + right) / 2; i++){
            int tmp = nums[i];
            nums[i] = nums[right - i + left];
            nums[right - i + left] = tmp;
        }
    }


    void nextPermutation(vector<int>& nums) {
        int n = nums.size();
        if (n <= 1)
            return;

        int pos = n - 1;
        while (pos > 0 && nums[pos-1] >= nums[pos]){ // 從後往前遞增,等號問題
            pos--;
        }
        if (pos > 0){

            //int val = nums[pos - 1];
            // 找到val之後的比 val大的最小的一個數
            int j = n - 1;
            while (nums[j] <= nums[pos-1]){
                j--;
            }

            // swap
            int tmp = nums[j];
            nums[j] = nums[pos-1];
            nums[pos-1] = tmp;

            // reverse val之後的所有數
            rev(nums, pos, n - 1);
        }
        else{
            rev(nums, 0, n - 1);
        }
    }
};

60. Permutation Sequence

題目地址

題目求解

求序列的第k個序列

利用數字規律,遞迴求解,全排列共n!種

class Solution {
public:

    string ans;

    vector<int> jieceng;

    void dfs(string v, int n, int k) //遞迴
    {
        if (n == 0)
            return;

        int index = n - 1;
        for (int i = 1; i < n; i++)
        {
            if (k <= i * jieceng[n - 1])
            {
                index = i - 1;
                break;
            }
        }

        //printf("%c",v[index]);
        ans += v[index];

        v.erase(v.begin() + index);

        dfs(v, n - 1, k - index*jieceng[n - 1]);

    }

    string getPermutation(int n, int k) {

        ans = "";
        jieceng.resize(n + 1);
        jieceng[0] = 1;

        for (int i = 1; i <= n; i++)
        {
            jieceng[i] = jieceng[i - 1] * i;
        }
        if (k <= 0 || k > jieceng[n])
        {
            return ans;
        }

        string s = "";
        for (int i = 1; i <= n; i++)
            s += (i + '0');

        dfs(s, n, k);

        return ans;
    }
};