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

Example:

Input: [1,2,3]
Output:
[
[1,2,3],
[1,3,2],
[2,1,3],
[2,3,1],
[3,1,2],
[3,2,1]
]

这道题是求全排列问题,给的输入数组没有重复项,这跟之前的那道 Combinations 和类似,解法基本相同,但是不同点在于那道不同的数字顺序只算一种,是一道典型的组合题,而此题是求全排列问题,还是用递归 DFS 来求解。这里需要用到一个 visited 数组来标记某个数字是否访问过,然后在 DFS 递归函数从的循环应从头开始,而不是从 level 开始,这是和 Combinations 不同的地方,其余思路大体相同。这里再说下 level 吧,其本质是记录当前已经拼出的个数,一旦其达到了 nums 数组的长度,说明此时已经是一个全排列了,因为再加数字的话,就会超出。还有就是,为啥这里的 level 要从0开始遍历,因为这是求全排列,每个位置都可能放任意一个数字,这样会有个问题,数字有可能被重复使用,由于全排列是不能重复使用数字的,所以需要用一个 visited 数组来标记某个数字是否使用过,代码如下:

解法一:

class Solution {
public:
vector<vector<int>> permute(vector<int>& num) {
vector<vector<int>> res;
vector<int> out, visited(num.size(), );
permuteDFS(num, , visited, out, res);
return res;
}
void permuteDFS(vector<int>& num, int level, vector<int>& visited, vector<int>& out, vector<vector<int>>& res) {
if (level == num.size()) {res.push_back(out); return;}
for (int i = ; i < num.size(); ++i) {
if (visited[i] == ) continue;
visited[i] = ;
out.push_back(num[i]);
permuteDFS(num, level + , visited, out, res);
out.pop_back();
visited[i] = ;
}
}
};

上述解法的最终生成顺序为:[[1,2,3], [1,3,2], [2,1,3], [2,3,1], [3,1,2], [3,2,1]] 。

还有一种递归的写法,更简单一些,这里是每次交换 num 里面的两个数字,经过递归可以生成所有的排列情况。这里你可能注意到,为啥在递归函数中, push_back() 了之后没有返回呢,而解法一或者是 Combinations 的递归解法在更新结果 res 后都 return 了呢?其实如果你仔细看代码的话,此时 start 已经大于等于 num.size() 了,而下面的 for 循环的i是从 start 开始的,根本就不会执行 for 循环里的内容,就相当于 return 了,博主偷懒就没写了。但其实为了避免混淆,最好还是加上,免得和前面的搞混了,代码如下:

解法二:

class Solution {
public:
vector<vector<int>> permute(vector<int>& num) {
vector<vector<int>> res;
permuteDFS(num, , res);
return res;
}
void permuteDFS(vector<int>& num, int start, vector<vector<int>>& res) {
if (start >= num.size()) res.push_back(num);
for (int i = start; i < num.size(); ++i) {
swap(num[start], num[i]);
permuteDFS(num, start + , res);
swap(num[start], num[i]);
}
}
};

上述解法的最终生成顺序为:[[1,2,3], [1,3,2], [2,1,3], [2,3,1], [3,2,1], [3,1,2]]

最后再来看一种方法,这种方法是 CareerCup 书上的方法,也挺不错的,这道题是思想是这样的:

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

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

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

_ a_ a_ : a3a1a2, a1a3a2, a1a2a3

_ a_ a_ : a3a2a1, a2a3a1, a2a1a3

解法三:

class Solution {
public:
vector<vector<int>> permute(vector<int>& num) {
if (num.empty()) return vector<vector<int>>(, vector<int>());
vector<vector<int>> res;
int first = num[];
num.erase(num.begin());
vector<vector<int>> words = permute(num);
for (auto &a : words) {
for (int i = ; i <= a.size(); ++i) {
a.insert(a.begin() + i, first);
res.push_back(a);
a.erase(a.begin() + i);
}
}
return res;
}
};

上述解法的最终生成顺序为:[[1,2,3], [2,1,3], [2,3,1], [1,3,2], [3,1,2], [3,2,1]]

上面的三种解法都是递归的,我们也可以使用迭代的方法来做。其实下面这个解法就上面解法的迭代写法,核心思路都是一样的,都是在现有的排列的基础上,每个空位插入一个数字,从而生成各种的全排列的情况,参见代码如下:

解法四:

class Solution {
public:
vector<vector<int>> permute(vector<int>& num) {
vector<vector<int>> res{{}};
for (int a : num) {
for (int k = res.size(); k > ; --k) {
vector<int> t = res.front();
res.erase(res.begin());
for (int i = ; i <= t.size(); ++i) {
vector<int> one = t;
one.insert(one.begin() + i, a);
res.push_back(one);
}
}
}
return res;
}
};

上述解法的最终生成顺序为:[[3,2,1], [2,3,1], [2,1,3], [3,1,2], [1,3,2], [1,2,3]]

下面这种解法就有些耍赖了,用了 STL 的内置函数 next_permutation(),专门就是用来返回下一个全排列,耳边又回响起了诸葛孔明的名言,我从未见过如此...投机取巧...的解法!

解法五:

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

上述解法的最终生成顺序为:[[1,2,3], [1,3,2], [2,1,3], [2,3,1], [3,1,2], [3,2,1]]

Github 同步地址:

https://github.com/grandyang/leetcode/issues/46

类似题目:

Next Permutation

Permutations II

Permutation Sequence

Combinations

参考资料:

https://leetcode.com/problems/permutations/

https://leetcode.com/problems/permutations/discuss/18462/Share-my-three-different-solutions

https://leetcode.com/problems/permutations/discuss/18255/Share-my-short-iterative-JAVA-solution

https://leetcode.com/problems/permutations/discuss/18239/A-general-approach-to-backtracking-questions-in-Java-(Subsets-Permutations-Combination-Sum-Palindrome-Partioning)

LeetCode All in One 题目讲解汇总(持续更新中...)

[LeetCode] Permutations 全排列的更多相关文章

  1. leetcode Permutations II 无重全排列

    作者:jostree  转载请注明出处 http://www.cnblogs.com/jostree/p/4051169.html 题目链接:leetcode Permutations II 无重全排 ...

  2. [CareerCup] 9.5 Permutations 全排列

    9.5 Write a method to compute all permutations of a string. LeetCode上的原题,请参加我之前的博客Permutations 全排列和P ...

  3. 每日一题-——LeetCode(46)全排列

    题目描述: 给定一个没有重复数字的序列,返回其所有可能的全排列.输入: [1,2,3]输出:[ [1,2,3], [1,3,2], [2,1,3], [2,3,1], [3,1,2], [3,2,1] ...

  4. LeetCode:全排列II【47】

    LeetCode:全排列II[47] 参考自天码营题解:https://www.tianmaying.com/tutorial/LC47 题目描述 给定一个可包含重复数字的序列,返回所有不重复的全排列 ...

  5. LeetCode:全排列【46】

    LeetCode:全排列[46] 题目描述 给定一个没有重复数字的序列,返回其所有可能的全排列. 示例: 输入: [1,2,3] 输出: [ [1,2,3], [1,3,2], [2,1,3], [2 ...

  6. LeetCode 47——全排列 II

    1. 题目 2. 解答 在 LeetCode 46--全排列 中我们已经知道,全排列其实就是先确定某一个位置的元素,然后余下就是一个子问题.在那个问题中,数据没有重复,所以数据中的任意元素都可以放在最 ...

  7. [LeetCode] Permutations II 全排列之二

    Given a collection of numbers that might contain duplicates, return all possible unique permutations ...

  8. [LeetCode] 46. Permutations 全排列

    Given a collection of distinct integers, return all possible permutations. Example: Input: [1,2,3] O ...

  9. [leetcode]46. Permutations全排列(给定序列无重复元素)

    Given a collection of distinct integers, return all possible permutations. Input: [1,2,3] Output: [ ...

随机推荐

  1. 【WP8.1】WebView笔记

    之前在WP8的时候做过WebBrowser相关的笔记,在WP8.1的WebView和WebBrowser有些不一样,在这里做一些笔记 下面分为几个部分 1.禁止缩放 2.JS通知后台C#代码(noti ...

  2. WPF's Style BasedOn

    <Style x:Key="BasedStyle" BasedOn="{x:Null}" TargetType="{x:Type Control ...

  3. 全局变量:global与$GLOBALS的区别和使用

    今天在写框架的时候想把SaeMySQL初始化之后作为全局变量使用.但是后来发现PHP中的全局变量和Java或者OC中的全局变量还是有较大区别的.下面记录一下php里面的global的使用相关注意事项. ...

  4. Mac OS X搭建C#开发环境

    在Mac下想要用C#语言的话,首先得有个跨平台的.Net环境-Mono http://www.mono-project.com/ 有了Mono平台之后,还得有一个好工具:目前比较好的IDE是Xmari ...

  5. bzoj2820--莫比乌斯反演

    题目大意: 给定N, M,求1<=x<=N, 1<=y<=M且gcd(x, y)为质数的(x, y)有多少对. 推导: 设n<=m ans=  = 由于gcd(i,j)= ...

  6. Node.js写文件的三种方法

    Node.js写文件的三种方式: 1.通过管道流写文件 采用管道传输二进制流,可以实现自动管理流,可写流不必当心可读流流的过快而崩溃,适合大小文件传输(推荐) var readStream = fs. ...

  7. 使用insertBefore实现insertAdjacentHTML()

    Element.insertAdjacentHTML()方法由IE引入,并在HTML5中标准化,它将任意的HTML标记字符串插入到指定的元素“相邻”的位置. insertAdjacentHTML()有 ...

  8. ipad和iphone的适配

    关于xib或者storybord下iphone的横竖屏的适配以及ipad的适配 ios8出现了Size Classes,解决了各种屏幕适配的问题,他把屏幕的宽和高分别分成了三种,把屏幕总共分成了九种情 ...

  9. django 第二天 制作小demo

    创建虚拟目录 mkdir ~/virtualenvs mkdir ~/virtualenvs/myprojectenv virtualenv ~/virtualenvs/myprojectenv 激活 ...

  10. 关于WCF测试时出现无法从***获取元数据问题

    在我们已经创建成功一个WCF服务后,通过本机localhost访问和测试均没有任何问题.但是寄宿在IIS/其他平台下时便会出现以下的错误信息 1.使用WCF Test Client错误 2.通过C#引 ...