【算法总结】排列组合的序列产生问题

1. Next Permutation

  首先,从最尾端开始往前寻找两个相邻元素,令第一元素为 *i,第二元素为 *ii,且满足 *i < *ii;找到这样一组相邻元素后,再从尾端开始往前检验,找出第一个大于 *i 的元素,令为 *j,将 i,j 元素对调,再将 ii 之后的所有元素颠倒排列。

 1 void nextPermutation(vector<int>& nums) {
 2         if(nums.empty())
 3             return;
 4         int n = nums.size();
 5         for (int i = n - 2; i >=0; --i) {
 6             if (nums[i] >= nums[i + 1])
 7                 continue;
 8             int j = n - 1;
 9             while (j >= 0 && nums[j] <= nums[i]) --j;
10             swap(nums[i], nums[j]);
11             reverse(nums.begin() + i + 1, nums.end());
12             return;
13         }
14         // 进行至最前面,重排
15         reverse(nums.begin(), nums.end());
16     }

 

2.Prev Permutation

  首先,从最尾端开始往前寻找两个相邻元素,令第一元素为 *i,第二元素为 *ii,且满足 *i  > *ii;找到这样一组相邻元素后,再从尾端开始往前检验,找出第一个小于*i 的元素,令为 *j,将 i,j 元素对调,再将 ii 之后的所有元素颠倒排列。

 1 void prevPermutation(vector<int>& nums) {
 2         if(nums.empty())
 3             return;
 4         int n = nums.size();
 5         for (int i = n - 2; i >=0; --i) {
 6             if (nums[i] <= nums[i + 1])
 7                 continue;
 8             int j = n - 1;
 9             while (j >= 0 && nums[j] >= nums[i]) --j;
10             swap(nums[i], nums[j]);
11             reverse(nums.begin() + i + 1, nums.end());
12             return;
13         }
14         reverse(nums.begin(), nums.end());
15     }

 

3. Permutations(全排列)

   (1)回溯法

 1 vector<vector<int>> permute(vector<int>& nums) {
 2         vector<vector<int>> res;
 3         vector<int> cur;
 4         vector<bool> visited(nums.size(), false);
 5         
 6         dfs(nums, res, cur, visited);
 7         
 8         return res;
 9     }
10     
11     void dfs(const vector<int>& nums, vector<vector<int>>& res, vector<int>& cur, vector<bool>& visited) {
12         if (cur.size() == nums.size()) {
13             res.push_back(cur);
14             return;
15         }
16         
17         for (int i = 0; i < nums.size(); ++i) {
18             if (visited[i] == false) {
19                 cur.push_back(nums[i]);
20                 visited[i] = true;
21                 dfs(nums, res, cur, visited);
22                 cur.pop_back();
23                 visited[i] = false;
24             }
25         }
26     }

  (2)递归 1:

 1 vector<vector<int>> permute(vector<int>& nums) {
 2         vector<vector<int>> res;
 3         
 4         recursive(nums, res, 0);
 5         
 6         return res;
 7     }
 8     
 9     void recursive(vector<int>& nums, vector<vector<int>>& res, int start) {
10         if (start >= nums.size()) {
11             res.push_back(nums);
12         }
13         for (int i = start; i < nums.size(); ++i) {
14             swap(nums[start], nums[i]);
15             recursive(nums, res, start + 1);
16             swap(nums[start], nums[i]);
17         }
18     }

    递归2:

当n=1时,数组中只有一个数a1,其全排列只有一种,即为a1

当n=2时,数组中此时有a1a2,其全排列有两种,a1a2和a2a1,那么此时我们考虑和上面那种情况的关系,我们发现,其实就是在a1的前后两个位置分别加入了a2

当n=3时,数组中有a1a2a3,此时全排列有六种,分别为a1a2a3, a1a3a2, a2a1a3, a2a3a1, a3a1a2, 和 a3a2a1。那么根据上面的结论,实际上是在a1a2和a2a1的基础上在不同的位置上加入a3而得到的。

  (3)借用next_permutation的函数

 4. The Kth Permutation Sequence

  The set [1,2,3,…,n] contains a total of n! unique permutations. Given n and k, return the kth permutation sequence.

 1 string getPermutation(int n, int k) {
 2         string res;
 3         string dict = "123456789";
 4         int factorial = 1;
 5         for (int i = 1; i < n; ++i) {
 6             factorial *= i;
 7         }
 8         --k;
 9         while (n--) {
10             int pos = k / factorial;
11             res += dict[pos];
12             k %= factorial;
13             factorial /= (n ? n : 1);
14             dict.erase(pos, 1);
15         }
16         return res;
17     }

 

 

 

 

posted @ 2018-03-26 10:17  Vincent丶丶  阅读(472)  评论(0编辑  收藏  举报