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. [.NET Core].NET Core R2安装教程及Hello示例

    前言 前几天.NET Core发布了.NET Core 1.0.1 R2 预览版,之前想着有时间尝试下.NET Core.由于各种原因,就没有初试.刚好,前几天看到.NET Core发布新版本了,决定 ...

  2. Shell脚本编程30分钟入门

    Shell脚本编程30分钟入门 转载地址: Shell脚本编程30分钟入门 什么是Shell脚本 示例 看个例子吧: #!/bin/sh cd ~ mkdir shell_tut cd shell_t ...

  3. 利用scp传输文件

    在linux下一般用scp这个命令来通过ssh传输文件. 从服务器上下载文件 scp username@servername:/path/filename /var/www/local_dir(本地目 ...

  4. java接口调用——webservice就是一个RPC而已

    很多新手一听到接口就蒙逼,不知道接口是什么!其实接口就是RPC,通过远程访问别的程序提供的方法,然后获得该方法执行的接口,而不需要在本地执行该方法.就是本地方法调用的升级版而已,我明天会上一篇如何通过 ...

  5. powerdesigner显示列描述信息

    将Comment中的字符COPY至Name中 -------------------------------------------------- Option   Explicit Validati ...

  6. datatables中的Options总结(2)

    datatables中的Options总结(2) 五.datatable,列 columnDefs.targets 分配一个或多个列的列定义. columnDefs 设置列定义初始化属性. colum ...

  7. 在网站开发中很有用的8个 jQuery 效果【附源码】

    jQuery 作为最优秀 JavaScript 库之一,改变了很多人编写 JavaScript 的方式.它简化了 HTML 文档遍历,事件处理,动画和 Ajax 交互,而且有成千上万的成熟 jQuer ...

  8. 判断终端的js

    $(function(){ var sUserAgent = navigator.userAgent.toLowerCase(); var bIsIpad = sUserAgent.match(/ip ...

  9. JAVA-堆区,栈区,方法区。

    转载:http://blog.csdn.net/wangxin1982314/article/details/50293241 堆区: 村线程操纵的数据(对象形式存放) 1 存储的全部是对象,每个对象 ...

  10. iOS HTTP访问网络受限

    HTTP访问网络受限,只需要在项目工程里的Info.plist添加 <key>NSAppTransportSecurity</key> <dict> <key ...