全排列问题。经常使用的排列生成算法有序数法、字典序法、换位法(Johnson(Johnson-Trotter)、轮转法以及Shift cursor cursor* (Gao & Wang)法。

【题目】

Given a collection of numbers, return all possible permutations.

For example,

[1,2,3] have the following permutations:

[1,2,3][1,3,2][2,1,3][2,3,1][3,1,2],
and [3,2,1].

【暴力递归】

这是比較直观的思路。可是也有要注意的地方。刚開始写的时候,没有注意到list是共用的。所曾经面得到的答案后面会改掉而导致错误。

public class Solution {
List<List<Integer>> ret = new ArrayList<List<Integer>>(); public List<List<Integer>> permute(int[] num) {
int len = num.length;
if (len == 0) return ret; List<Integer> list = new ArrayList<Integer>();
run(list, num);
return ret;
} public void run(List<Integer> list, int[] num) {
if (list.size() == num.length) {
//注意这里要又一次new一个list。要不然后面会被改动
List<Integer> res = new ArrayList<Integer>();
res.addAll(list);
ret.add(res);
return;
}
for (int i = 0; i < num.length; i++) {
if (list.contains(num[i])) {
continue;
}
list.add(num[i]);
run(list, num);
list.remove(list.indexOf(num[i])); //不要忘记这一步
}
}
}

【字典序法】

C++的STL库里面有nextPermutation()方法。事实上现就是字典序法。

下图简单明了地介绍了字典序法

归纳一下为:

比如,1234的全排列例如以下:

watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvbGppYWJpbg==/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast" alt="">

【代码实现】

因为Java的list传參传的是地址,所以每次加入时都要记得又一次new一个新的list加入到结果集中。否则加入到结果集中的原list会被后面的操作改变。

public class Solution {
public List<List<Integer>> permute(int[] num) {
List<List<Integer>> ret = new ArrayList<List<Integer>>(); int len = num.length;
if (len == 0) return ret; Arrays.sort(num); //字典序法需先对数组升序排序 //数组转为list
List<Integer> list0 = new ArrayList<Integer>();
for (int i = 0; i < len; i++) {
list0.add(num[i]);
} //把原始数组相应的list加入到结果中。不能直接加入list0,由于后面它会一直变化
List<Integer> ll = new ArrayList<Integer>();
ll.addAll(list0);
ret.add(ll); //逐次找下一个排列
for (int i = 1; i < factorial(len); i++) {
ret.add(nextPermutation(list0));
}
return ret;
} /***字典序法生成下一个排列***/
public List<Integer> nextPermutation(List<Integer> num) {
//找到最后一个正序
int i = num.size()-1;
while(i > 0 && num.get(i-1) >= num.get(i)){
i--;
} //找到最后一个比num[i-1]大的数
int j = i;
while(j < num.size() && num.get(j) > num.get(i-1)) {
j++;
} //交换num[i-1]和num[j-1]
int tmp = num.get(i - 1);
num.set(i - 1, num.get(j - 1));
num.set(j - 1, tmp); //反转i以后的数
reverse(num, i, num.size()-1); List<Integer> ret = new ArrayList<Integer>();
ret.addAll(num);
return ret;
} public void reverse(List<Integer> list, int begin, int end) {
for(int i = begin, j = end; i < j; i++) {
list.add(i, list.remove(j));
}
} public int factorial(int n) {
return (n == 1 || n == 0) ? 1 : factorial(n - 1) * n;
}
}

上面的实现须要先对原数组升序排序。以下对nextPermutation(List<Integer> num)改进后就不用对num排序了。

    /***字典序法生成下一个排列***/
public List<Integer> nextPermutation(List<Integer> num) {
//找到最后一个正序
int i = num.size()-1;
while(i > 0 && num.get(i-1) >= num.get(i)){
i--;
} //有了这个推断就不用num最初是按升序排好的了
if (i == 0) {
reverse(num, 0, num.size()-1);
List<Integer> ret = new ArrayList<Integer>();
ret.addAll(num);
return ret;
} //找到最后一个比num[i-1]大的数
int j = i;
while(j < num.size() && num.get(j) > num.get(i-1)) {
j++;
} //交换num[i-1]和num[j-1]
int tmp = num.get(i - 1);
num.set(i - 1, num.get(j - 1));
num.set(j - 1, tmp); //反转i以后的数
reverse(num, i, num.size()-1); List<Integer> ret = new ArrayList<Integer>();
ret.addAll(num);
return ret;
}

欢迎高人对上述代码继续优化!

相关题目:【LeetCode】Next Permutation 解题报告 和 【LeetCode】Permutations II 解题报告

【LeetCode】Permutations 解题报告的更多相关文章

  1. LeetCode: Permutations 解题报告

    Permutations Given a collection of numbers, return all possible permutations. For example,[1,2,3] ha ...

  2. 【LeetCode】46. Permutations 解题报告(Python & C++)

    作者: 负雪明烛 id: fuxuemingzhu 个人博客:http://fuxuemingzhu.cn/ 目录 题目描述 解题方法 方法一:库函数 方法二:递归 方法三:回溯法 日期 题目地址:h ...

  3. leetcode—Palindrome 解题报告

    1.题目描述 Given a string s, partition s such that every substring of the partition is a palindrome. Ret ...

  4. LeetCode C++ 解题报告

    自己做得LeetCode的题解,使用C++语言. 说明:大多数自己做得,部分参考别人的思路,仅供参考; GitHub地址:https://github.com/amazingyyc/The-Solut ...

  5. C++版 - 剑指offer之面试题37:两个链表的第一个公共结点[LeetCode 160] 解题报告

    剑指offer之面试题37 两个链表的第一个公共结点 提交网址: http://www.nowcoder.com/practice/6ab1d9a29e88450685099d45c9e31e46?t ...

  6. LeetCode: Subsets 解题报告

    Subsets Given a set of distinct integers, S, return all possible subsets. Note: Elements in a subset ...

  7. LeetCode: Triangle 解题报告

    Triangle Given a triangle, find the minimum path sum from top to bottom. Each step you may move to a ...

  8. LeetCode: isSameTree1 解题报告

    isSameTree1 Given two binary trees, write a function to check if they are equal or not. Two binary t ...

  9. LeetCode: Combinations 解题报告

    Combinations Given two integers n and k, return all possible combinations of k numbers out of 1 ... ...

随机推荐

  1. 训练深度学习网络时候,出现Nan 或者 震荡

    出现Nan : 说法1: 说法2:说法3:     震荡 : 分析原因:  1:训练的batch_size太小 1.  当数据量足够大的时候可以适当的减小batch_size,由于数据量太大,内存不够 ...

  2. [转]Spring mvc interceptor配置拦截器,没有登录跳到登录页

    <?xml  version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.s ...

  3. php分享十五:php的数据库操作

    一:术语解释: What is an Extension? API和扩展不能理解为一个东西,因为扩展不一定暴露一个api给用户 The PDO MySQL driver extension, for ...

  4. JDK1.7新特性,语言篇

    1. 可以用二进制表达数字 可以用二进制表达数字(加前缀0b/0B),包括:byte, short, int, long // 可以用二进制表达数字(加前缀0b/0B),包括:byte, short, ...

  5. oracle11g exp导出问题:部分表导不出来

    在oracle导出表的命令exp时候发现一个问题,就是部分表全然的导不出来,经检查发现仅仅要是表为空的都会导不出来. 在例如以下表中发现segment_created都为NO的是导不出来的,经查询后, ...

  6. 菜鸟学Java(三)——JSTL标签之核心标签

    JSTL(JSP Standard Tag Library ,JSP标准标签库)是一个实现 Web应用程序中常见的通用功能的定制标记库集,这些功能包括迭代和条件判断.数据管理格式化.XML 操作以及数 ...

  7. SQL 中 replace 替换字符串中的字符 ''

    update CfmRcd set reconsource=replace(reconsource,'''',''), cmffile =replace(cmffile,'''',''), cfmda ...

  8. linux命令(41):文件和文件夹的颜色

    各个颜色的文件分别代表的是:蓝色表示目录:绿色表示可执行文件:红色表示压缩文件:浅蓝色表示链接文件:灰色表示其它文件:红色闪烁表示链接的文件有问题了:黄色是设备文件,包括block, char, fi ...

  9. Ubuntu 14.04环境变量修改

    因在开发编译时是找不到命令,原因是将路径添加到环境变量,如何设置环境变量,搜索一下,找到以下关于环境变量设置的几个文件及何时执行. 首先要认识几个和环境变量有关的文件: /etc/profile —— ...

  10. muduo源码分析:组成结构

    muduo整体由许多类组成: 这些类之间有一些依赖关系,如下: