全排列问题。经常使用的排列生成算法有序数法、字典序法、换位法(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. [转]cubemap soft shadow

    https://community.arm.com/graphics/b/blog/posts/dynamic-soft-shadows-based-on-local-cubemap

  2. mysql性能测试(索引)

    首先,使用Talend随机生成一千万条数据: 数据库表中现在有1千万+的数据: mysql> select count(*) from zhangchao; +----------+ | cou ...

  3. Java:集合,Arrays工具类用法

    1. 描述 Arrays工具类提供了针对数组(Array)的一些操作,比如排序.搜索.将数组(Array)转换列表(List)等等,都为静态(static)方法: binarySearch - 使用二 ...

  4. 关于 sql server 数据库权限乱七八糟的一些东西

    研究权限这些东西主要是因为今天正好在折腾数据库备份相关的东西,备份好说,备份完了就完了. 但是恢复备份的时候,需要先让数据库脱机,然后恢复,然后再联机,嗯,问题就出在联机上了. 根据 MSDN 的说法 ...

  5. [LintCode] Subarray Sum & Subarray Sum II

    Subarray Sum Given an integer array, find a subarray where the sum of numbers is zero. Your code sho ...

  6. javascript读取xml文件读取节点数据的例子

    分享下用javascript读取xml文件读取节点数据方法. 读取的节点数据,还有一种情况是读取节点属性数据. <head> <title></title> < ...

  7. APACHE LOG4J™ 2

    最近服务端开发需要用Log系统,于是研究了下APACHE下的Log框架. 目前日志系统,支持的语言有C++,PHP,.NET,JAVA.当然我是用Java服务端,选择用log4j吧.但突然发现log4 ...

  8. Atitit codeblock c++开发环境建立attilax总结

    Atitit codeblock c++开发环境建立attilax总结 1.1. C++的重要意义 1 1.2. 项目ide的选项 1 1.3. 安装MinGW  (基于GCC的C++编译器)  50 ...

  9. 基于Xilinx Zynq Z7045 SoC的CNN的视觉识别应用

    基于Xilinx Zynq Z7045 SoC的CNN的视觉识别应用 由 judyzhong 于 星期三, 08/16/2017 - 14:56 发表 作者:stark 近些年来随着科学技术的不断进步 ...

  10. [svc]Linux vmstat命令实战详解

    vmstat输出 注:是cpu 内存 磁盘 虚拟内存交换情况 io读写情况 vmstat命令是最常见的Linux/Unix监控工具,可以展现给定时间间隔的服务器的状态值,包括服务器的CPU使用率,内存 ...