题目:Given a collection of distinct numbers, return all possible permutations.
解析:本题可以有两种方法解决
方法一:1)将第一个元素依次与所有元素进行交换;
2)交换后,可看作两部分:第一个元素及其后面的元素;
3)后面的元素又可以看作一个待排列的数组,递归,当剩余的部分只剩一个元素时,得到一个排列;
4)将第1步中交换的元素还原,再与下一个位元素交换。
重复以上4步骤,直到交换到最后一个元素。(参考剑指offer讲解)
方法二:字典序,根据当前序列,生成下一个序列,交换 + 逆序。
代码:
方法一:非字典序
public static void main(String[] args) { // TODO Auto-generated method stub //定义数组 int[] array = {1,2,3}; List<List<Integer>> list = new ArrayList<List<Integer>>(); int start = 0; //不去重,非字典序 list = getPermutations(array, list, start); }
/** * 方法一 * 不去重,非字典序 * @param array * @return */ public static List<List<Integer>> getPermutations(int[] array,List<List<Integer>> list,int start){ if(start == array.length){//遍历到最后一个,得到一个排列 List<Integer> item = new ArrayList<Integer>(array.length); for(int i = 0,len = array.length; i < len; ++i) item.add(array[i]); list.add(item); } else { //需要交换的次数 for(int i = start,len = array.length; i < len; ++i){ //第一个元素,依次与后面的所有元素进行交换 //交换 swap(array,i,start); //递归在循环里 getPermutations(array,list,start + 1); //字符串分为两部分,第一个元素及第一个元素之后的所有元素 //回溯 swap(array,i,start); } } return list; }
方法二:字典序,调用next permutation
/** * 方法二 * 不去重,字典序 * @return */ public static List<List<Integer>> permutations(int[] array,List<List<Integer>> list){ //一共需要进行 n! 次运算 for(int i = 0,len = factorial(array.length); i < len; ++i){ if(i == 0){ List<Integer> item = new ArrayList<Integer>(); for(int j = 0,l = array.length; j < l; ++j) item.add(array[j]); list.add(item); } else { List<Integer> item = new ArrayList<Integer>(); item = nextPermutation(array); list.add(item); } } return list; } /** * 获取下一个字典序的排列 * @return */ public static List<Integer> nextPermutation(int[] nums){ if(nums == null) return null; if(nums.length == 0) return new ArrayList<Integer>(); //长度为1的数组 if (nums.length == 1) { return new ArrayList<Integer>(nums[0]); } //存储结果 List<Integer> result = new ArrayList<Integer>(); //从后向前找到第一个不满足逆序的元素 int i = nums.length - 2; for(; i >= 0 && nums[i] > nums[i + 1]; --i); //从i+1位置开始,向后查找比nums[i]大的最小元素 if(i >= 0){ int j = i + 1; for(; j < nums.length && nums[j] > nums[i]; ++j); swap(nums,i,j - 1); //交换,注意是同 j - 1交换 } //将i之后的元素逆置(这里包含一种特殊情况,若该排列已经是字典序中的最大了,则下一个序列应该是最小字典序,因此,直接在这里逆置即可) int k = nums.length - 1; i++; for(; i < k; i++, k--) swap(nums, i, k); for(int l = 0,len = nums.length; l < len; ++l) result.add(nums[l]); return result; }
时间: 2024-10-27 13:25:06