Permutation类型题目整理
1.permutations
Given a list of numbers, return all possible permutations.
For nums = [1,2,3]
, the permutations are:
[
[1,2,3],
[1,3,2],
[2,1,3],
[2,3,1],
[3,1,2],
[3,2,1]
]
显然需要需要用递归来找所有的全排列。关于这个递归,是返回找到的值加入到上层还是在把参数传到递归层,在递归层进行更新处理。对于分治策略,二叉树的问题,很明显左右子树能得到一个小问题的答案,大问题的答案是该小问题的答案的一个组合,那么用递归返回一个结果,在上层进行结合处理比较方便。对于这个题目,每次递归要做的事情是往下找permutations的下一个数字,在递归层处理结果更加自然。
注意深刻理解这个递归要干的事情,每一层分别是做什么的。
for (int i = 0; i < nums.length; i++) {
。。。
list.add(nums[i]);
helper(nums, result, list);
list.remove(list.size() - 1);
。。。
}
这个for循环其实是在便利nums数组,找到第一个合适的permutation的首字母,这也就是为什么找到第一个首字母的时候,我们要把它更新的结果里面。这时候需要找第二个字母,那么我们跳到第二层递归里面去找第二个,这也就是为什么,这个时候需要使用递归。当以当前首字母开头的permutations找到并且加入到全局结果里以后,我们需要找下一个合适的开头字母,所以要把当前的开头字母给清空,这也就是为什么需要做remove操作。
1 class Solution { 2 /** 3 * @param nums: A list of integers. 4 * @return: A list of permutations. 5 */ 6 public List<List<Integer>> permute(int[] nums) { 7 List<List<Integer>> result = new ArrayList<List<Integer>>(); 8 if (nums == null) { 9 return result; 10 } 11 List<Integer> list = new ArrayList<Integer>(); 12 helper(nums,result,list); 13 return result; 14 } 15 private void helper (int[] nums, List<List<Integer>> result, List<Integer> list) { 16 if (list.size() == nums.length) { 17 result.add(new ArrayList<Integer>(list)); 18 } 19 for (int i = 0; i < nums.length; i++) { 20 if (list.contains(nums[i])){ 21 continue; 22 } 23 list.add(nums[i]); 24 helper(nums, result, list); 25 list.remove(list.size() - 1); 26 } 27 } 28 }
2. Permutations II
Given a list of numbers with duplicate number in it. Find all unique permutations.
Example
For numbers [1,2,2]
the unique permutations are:
[
[1,2,2],
[2,1,2],
[2,2,1]
]
注意3点, 1. 对于有重复的情况,用visited[]数组处理,判断这个数是否已经遍历过了
2. 需要对数组进行排序,如果num是int[] 那么用Arrays.sort
如果是ArrayList<Integer> 用Collections.sort
3.对于重复的情况,112, 11第一次出现时是valid, 但是当把第二个1作为开头,第一个1作为第二时是invalid,所以添加了下面的判断条件:
(i != 0 && nums.get(i) == nums.get(i - 1) && visited[i - 1] == 0)
针对这个情况,下面是反例:
wrong answer:
1 public class Solution { 2 public List<List<Integer>> permuteUnique(int[] nums) { 3 List<List<Integer>> result = new ArrayList<List<Integer>>(); 4 if (nums == null || nums.length == 0) { 5 return result; 6 } 7 List<Integer> list = new ArrayList<Integer>(); 8 int[] visited = new int[nums.length]; 9 Arrays.sort(nums); 10 helper(nums, result, list, visited); 11 return result; 12 } 13 private static void helper(int[] nums, List<List<Integer>> result, List<Integer> list, int[] visited) { 14 if (list.size() == nums.length) { 15 result.add(new ArrayList(list)); 16 return; 17 } 18 19 for (int i = 0; i < nums.length; i++) { 20 if (visited[i] == 1 || (i != 0 && nums[i] == nums[i - 1] && visited[i - 1] == 0)) { 21 continue; 22 } 23 visited[i] = 1; 24 list.add(nums[i]); 25 helper(nums, result, list, visited); 26 list.remove(list.size() - 1); 27 visited[i] = 0; 28 } 29 } 30 }
3.Next Permutation
1,2,3
→ 1,3,2
3,2,1
→ 1,2,3
1,1,5
→ 1,5,1
1 public class Solution { 2 /** 3 * @param nums: an array of integers 4 * @return: return nothing (void), do not return anything, modify nums in-place instead 5 */ 6 public int[] nextPermutation(int[] nums) { 7 if (nums == null || nums.length == 0) { 8 return nums; 9 } 10 int size = nums.length; 11 int violation = -1; 12 // search for first violation 13 for (int i = size - 1; i > 0; i--) { 14 if (nums[i - 1] < nums[i]) { 15 violation = i - 1; 16 break; 17 } 18 } 19 20 // if can not find violation, we need to sawp all the array 21 if (violation == -1) { 22 int i = 0, j = size - 1; 23 while(i < j) { 24 swap(nums, i++, j--); 25 } 26 return nums; 27 } 28 29 30 // search swap index 31 int index = -1; 32 for (int i = size - 1; i > violation; i--) { 33 if (nums[i] > nums[violation]) { 34 index = i; 35 break; 36 } 37 } 38 //swap violation and index 39 swap(nums, violation, index); 40 41 //swap the tail part after the violation 42 int i = violation + 1, j = size - 1; 43 while(i < j) { 44 swap(nums, i++, j--); 45 } 46 return nums; 47 } 48 private static void swap (int[] nums, int i, int j) { 49 int temp = nums[i]; 50 nums[i] = nums[j]; 51 nums[j] = temp; 52 return; 53 } 54 }
4. Permutation Sequence
1 class Solution { 2 public: 3 string getPermutation(int n, int k) { 4 string str = string("123456789").substr(0, n); 5 string res(n, ' '); 6 for(int i = 0; i < n; i++) 7 res[i] = helper(str, k); 8 return res; 9 } 10 //以s中字符构造的全排列中,返回第k个排列的第一个字符,并且删除s中该字符 11 //s中字符递增有序 12 char helper(string &s, int &k) 13 { 14 int tmp = factorial(s.size()-1), i = (k-1)/tmp; 15 char res = s[i]; 16 s.erase(i, 1); 17 k -= i*tmp;//更新k 18 return res; 19 } 20 //求正整数n的阶乘 21 int factorial(int n) 22 { 23 int res = 1; 24 for(int i = 2; i <= n; i++) 25 res *= i; 26 return res; 27 } 28 };
java的代码相对复杂一点,方法是一样的,达到目的的实现有点绕
1 public class Solution { 2 3 public String getPermutation(int n, int k) { 4 StringBuilder sb = new StringBuilder(); 5 boolean[] used = new boolean[n]; 6 7 k = k - 1; 8 int factor = 1; 9 for (int i = 1; i < n; i++) { 10 factor *= i; 11 } 12 13 for (int i = 0; i < n; i++) { 14 int index = k / factor; 15 k = k % factor; 16 for (int j = 0; j < n; j++) { 17 if (used[j] == false) { 18 if (index == 0) { 19 used[j] = true; 20 sb.append((char) ('0' + j + 1)); 21 break; 22 } else { 23 index--; 24 } 25 } 26 } 27 if (i < n - 1) { 28 factor = factor / (n - 1 - i); 29 } 30 } 31 32 return sb.toString(); 33 } 34 }