个人记录-LeetCode 46. Permutations
2016-12-09 20:12
211 查看
问题:
Given a collection of distinct numbers, return all possible permutations.
For example,
[1,2,3] have the following permutations:
问题要求:得到指定数组的全排列。
代码示例:
1、暴力递归
回忆一下我们通常求全排列的方法。
例如有3个数,它们全排列的大小为:
第1个位置,可以为3个数中的任意一个,共有3种选择;
第2位置,在选完第1个位置的数后,可以为剩下2个数中的任意一个,共有2种选择;
第3个位置,在选完第1个和第2个位置的数后,只有1种选择。
因此,整体共有6种选择。
我们也可以按照这种思路写代码:
2、改进
前一种方法选择每个位置的数时,需要判断其它数是否已经被选择过,比较耗费时间。这种过程我们称为“为位置选数”。
下面这个过程,可以称为“为数选位置”。
第1个数与后续每个数交换位置,得到新数组后,在新数组的基础上递归。
此时,第1个数分别放到了0~n-1的位置上。
然后,开始为第2个数选位置。
由于第1个数和第2个数交换过,因此已经有一个递归序列,处理第2个数放到第1个位置的情况了。
为了避免重复,将第2个数与其后的每个数交换位置,得到下一个新数组,然后继续在此基础上递归。
此时,第2个数分别放在了1~n-1的位置上。
以此类推,得到最终结果。
不过这种方式会有重复的结果。
Given a collection of distinct 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], [3,2,1] ]
问题要求:得到指定数组的全排列。
代码示例:
1、暴力递归
回忆一下我们通常求全排列的方法。
例如有3个数,它们全排列的大小为:
第1个位置,可以为3个数中的任意一个,共有3种选择;
第2位置,在选完第1个位置的数后,可以为剩下2个数中的任意一个,共有2种选择;
第3个位置,在选完第1个和第2个位置的数后,只有1种选择。
因此,整体共有6种选择。
我们也可以按照这种思路写代码:
public class Solution { public List<List<Integer>> permute(int[] nums) { List<List<Integer>> result = new ArrayList<>(); if (nums == null || nums.length < 1) { return result; } //现将数组排序,这样相同的数字排在一起,可以跳过,避免重复结果 Arrays.sort(nums); //flag记录一个数字是否被选择过 boolean[] flag = new boolean[nums.length]; //path记录每次排列的结果 List<Integer> path = new ArrayList<>(); //无脑暴力递归 permute(nums, path, flag, result); return result; } private void permute(int[] nums, List<Integer> path, boolean[] flag, List<List<Integer>> result) { //已经完成了所有位置的选择,返回结果 if (path.size() == nums.length) { result.add(path); return; } boolean first = true; //prev记录当前位置,上一次选择的数 int prev = -1; for (int i = 0; i < nums.length; ++i) { if (!flag[i]) { if (first) { prev = nums[i]; first = false; } else { //避免在同一个位置,选择相同的数,避免重复 if (nums[i] == prev) { continue; } prev = nums[i]; } //生成新的位图 List<Integer> tempList = new ArrayList<>(path); boolean[] tempFlag = new boolean[nums.length]; System.arraycopy(flag, 0, tempFlag, 0, nums.length); //添加本次信息 tempFlag[i] = true; tempList.add(nums[i]); //继续递归 permute(nums, tempList, tempFlag, result); } } } }
2、改进
前一种方法选择每个位置的数时,需要判断其它数是否已经被选择过,比较耗费时间。这种过程我们称为“为位置选数”。
下面这个过程,可以称为“为数选位置”。
第1个数与后续每个数交换位置,得到新数组后,在新数组的基础上递归。
此时,第1个数分别放到了0~n-1的位置上。
然后,开始为第2个数选位置。
由于第1个数和第2个数交换过,因此已经有一个递归序列,处理第2个数放到第1个位置的情况了。
为了避免重复,将第2个数与其后的每个数交换位置,得到下一个新数组,然后继续在此基础上递归。
此时,第2个数分别放在了1~n-1的位置上。
以此类推,得到最终结果。
不过这种方式会有重复的结果。
public class Solution { public List<List<Integer>> permute(int[] nums) { List<List<Integer>> result = new ArrayList<>(); //仍然排序,避免重复 Arrays.sort(nums); //迭代 perm(result,nums,0,nums.length-1); return result; } public static void perm(List<List<Integer>> result, int[] nums, int start, int end) { //start记录此次交换的起始位置 if(start == end){ Integer[] tempNums = new Integer[nums.length]; for (int i = 0; i < nums.length; ++i) { tempNums[i] = nums[i]; } result.add(Arrays.asList(tempNums)); } else { boolean flag = true; int prev = -1; for(int i=start; i<=end; i++){ //以下这一段仍是避免重复 if (flag) { prev = nums[i]; flag = false; } else { //prev与nums[i]的比较,与1方法类似,避免重复交换 //nums[start]与nums[i]比较,避免某个位置与起始位置一致 if (prev == nums[i] || nums[start] == nums[i]) { continue; } else { prev = nums[i]; } } //交换当前起始位置和后续位置的数 int temp = nums[start]; nums[start] = nums[i]; nums[i] = temp; //继续迭代 perm(result, nums,start+1,end); //还原数组 temp = nums[start]; nums[start] = nums[i]; nums[i] = temp; } } } }
相关文章推荐
- 个人记录-LeetCode 3.Longest Substring Without Repeating Characters
- 个人记录-LeetCode 5.Longest Palindromic Substring
- 个人记录-LeetCode 21. Merge Two Sorted Lists
- 个人记录-LeetCode 26. Remove Duplicates from Sorted Array
- 个人记录-LeetCode 25. Reverse Nodes in k-Group
- 个人记录-LeetCode 1.Two Sum
- 个人记录-LeetCode 30. Substring with Concatenation of All Words
- 个人记录-LeetCode 19. Remove Nth Node From End of List
- 个人记录-LeetCode 18. 4Sum
- 个人记录-LeetCode 28. Implement strStr()
- 个人记录-LeetCode 6.ZigZag Conversion
- 个人记录-LeetCode 11. Container With Most Water
- 个人记录-LeetCode 10.Regular Expression Matching
- 个人记录-LeetCode 20. Valid Parentheses
- 个人记录-LeetCode 15. 3Sum
- 个人记录-LeetCode 4.Median of Two Sorted Arrays
- 个人记录-LeetCode 9.Palindrome Number
- 个人记录-LeetCode 13. Roman to Integer
- 个人记录-LeetCode 23. Merge k Sorted Lists
- 个人记录-LeetCode 29. Divide Two Integers