diff --git a/solutions/46. Permutations.md b/solutions/46. Permutations.md index dbe09de..9eaecc3 100644 --- a/solutions/46. Permutations.md +++ b/solutions/46. Permutations.md @@ -1,16 +1,34 @@ # [46. Permutations](https://leetcode.com/problems/permutations/) # 思路 -返回一个数组的所有排列,数组中元素没有重复。 +返回一个数组的所有排列,数组中元素没有重复。 +## 思路一、Next Permutation 如果做了[31. Next Permutation](https://leetcode.com/problems/next-permutation/)的话那这题就没什么问题了。稍有不同的是此题的数组元素没有重复而39题中可能重复。 所以此题可以使用STL中现成的next_permutation函数: > bool next_permutation (first, last)返回的是bool型,如果已经是最后一个排列了则返回false并将数组变成第一个排列(即按照从小到大排好序);否则返回true并将数组变成下一个排列。 此外还可以传入comp参数: next_permutation (first, last, comp)这样就可以自定义数组的大小规则。 另外也可手动实现这个函数,参见我的[31题题解](https://github.com/ShusenTang/LeetCode/blob/master/solutions/31.%20Next%20Permutation.md)。 -亲测使用STL中的要比手动实现慢很多。 +亲测使用STL中的要比手动实现慢很多。 + +## 思路二、DFS(常规思路,务必掌握) +根据经验,像这种要求出所有结果的集合,常规思路DFS递归求解。这里有两种DFS思路。 +### 普通DFS +用一个数组pmt记录此时的排列,还需要用到一个visited数组来标记某个数字是否访问过,然后每个DFS递归函数的for循环应从头开始(注意[77. Combinations题解](https://github.com/ShusenTang/LeetCode/blob/master/solutions/77.%20Combinations.md)中不是从头开始的,注意区别)。当pmt和nums一样长时说明pmt是一个全排列,此时应将pmt存放进结果数组res里并跳出当前递归。注意这里for循环应从头开始是因为这是求全排列(而不像77题那样求组合),每个位置都可能放任意一个数字,这样会有个问题,数字有可能被重复使用,由于全排列是不能重复使用数字的,所以我们需要用一个visited数组来标记某个数字是否使用过。 +### swap DFS +此题可以使用的另一种DFS是基于这样一种思路:每次交换num里面的两个数字,经过递归可以生成所有的排列情况。即第一次递归时,nums的第1个数字可以选择分别和第1、2...、n个数字交换;在第一次递归的某种情况的基础上,第二次递归可以让nums的第2个数字分别和第2、3...、n个数字进行交换......,我们利用一个参数start记录当前所在的递归层数(从0开始),当`start = n`时当前nums中就是一个之前未出现过的全排列,将其送入结果数组res中并跳出当前递归,这样经过n次递归就可以获得所有全排列。 + +## 思路三、 +最后再来看一种巧妙的方法: +* 当n=1时,数组中只有一个数a1,其全排列只有一种,即为a1; +* 当n=2时,数组中此时有a1a2,其全排列有两种即a1a2和a2a1。此时我们考虑和n=1时的关系,我们发现,其实就是在a1的前后两个位置分别加入了a2; +* 当n=3时,数组中有a1a2a3,此时全排列有六种,分别为a1a2a3、a1a3a2、a2a1a3、a2a3a1、a3a1a2和a3a2a1。对比n=2发现,实际上是在a1a2和a2a1的基础上在不同的位置上加入a3而得到的。 + +针对上述思路可以写出递归和迭代两种代码。 + # C++ -## 使用STL中的next_permutation +## 思路一、Next Permutation +### 使用STL中的next_permutation ``` C++ class Solution { public: @@ -24,7 +42,7 @@ public: } }; ``` -## 手动实现(亲测更快) +### 手动实现(亲测更快) ``` C++ class Solution { private: @@ -59,3 +77,112 @@ public: } }; ``` +## 思路二 +### 普通DFS +``` C++ +class Solution { +private: + void DFS(vector>&res, vector&pmt, vector&visited, const vector &nums){ + int n = nums.size(); + if(n == pmt.size()){ + res.push_back(pmt); + return; + } + for(int i = 0; i < n; i++){ + if(visited[i]) continue; + visited[i] = 1; + pmt.push_back(nums[i]); + DFS(res, pmt, visited, nums); + visited[i] = 0; + pmt.pop_back(); + } + } +public: + vector> permute(vector& nums) { + vector>res; + vectorpmt; + vectorvisited(nums.size(), 0); + DFS(res, pmt, visited, nums); + return res; + } +}; +``` +### swap DFS +``` C++ +class Solution { +private: + void DFS_swap(vector>&res, vector &nums, const int start){ + int n = nums.size(); + if(start >= n){ + res.push_back(nums); + return; + } + for(int i = start; i < n; i++){ + swap(nums[start], nums[i]); + DFS_swap(res, nums, start + 1); + swap(nums[start], nums[i]); + } + } +public: + vector> permute(vector& nums) { + vector>res; + DFS_swap(res, nums, 0); + return res; + } +}; +``` +## 思路三 +### 递归 +``` C++ +class Solution { +private: + void helper(vector>&res, const int curr_n, const vector &nums){ + if(curr_n == nums.size()) return; + if(curr_n == 0) res.push_back(vector(1, nums[0])); + else{ + int res_size = res.size(); + for(int i = 0; i < curr_n; i++){ // curr_n为复制次数 + for(int j = 0; j < res_size; j++){ + auto pmt = res[j]; + pmt.insert(pmt.begin() + i, nums[curr_n]); + res.push_back(pmt); + } + } + for(int i = 0; i < res_size; i++) + res[i].push_back(nums[curr_n]); + } + helper(res, curr_n + 1, nums); + } +public: + vector> permute(vector& nums) { + vector>res; + helper(res, 0, nums); + return res; + } +}; +``` +### 迭代 +``` C++ +class Solution { +public: + vector> permute(vector& nums) { + vector>res; + res.push_back(vector(1, nums[0])); + int curr_n = 1, n = nums.size(); + while(curr_n < n){ + int res_size = res.size(); + for(int i = 0; i < curr_n; i++) // curr_n为复制次数 + for(int j = 0; j < res_size; j++){ + auto pmt = res[j]; + pmt.insert(pmt.begin() + i, nums[curr_n]); + res.push_back(pmt); + } + for(int i = 0; i < res_size; i++) + res[i].push_back(nums[curr_n]); + curr_n++; + } + return res; + } +}; +``` +