Leetcode 46. Permutations & 47. Permutations II
2016-02-21 23:06
519 查看
46. Permutations
Total Accepted: 88129 TotalSubmissions: 253942 Difficulty: Medium
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],
and
[3,2,1].
Method 1:
自己写的,参照CTCI150中的思路,取出当前的result中的一个list,将目前的nums[i]的元素,加入到该list中的list.size()+1个位置,然后将结果加入result,并将之前的所有保存结果删除(size比这次放入的所有list小1)。
public class Solution { // O(n!) since N! permutations in total public List<List<Integer>> permute(int[] nums) { List<List<Integer>> res = new ArrayList<List<Integer>>(); if (nums == null) return res; for (int i=0; i<nums.length; i++) { insert(nums[i], res); } return res; } public void insert(int num, List<List<Integer>> res) { int size = res.size(); List<Integer> temp; if (size==0) { temp = new ArrayList<Integer>(); temp.add(num); res.add(temp); } else { for (int j=size-1; j>=0; j--) { temp = res.get(j); int tempSize = temp.size(); for (int k=0; k<=tempSize; k++){ List<Integer> perm = new ArrayList<Integer>(temp); perm.add(k,num); res.add(perm); } res.remove(j); } } }
运行时间:4ms
Method 2: (来源:https://cheonhyangzhang.wordpress.com/2015/09/21/46-leetcode-java-permutations-medium/ )
backtracking,每次取一个数,然后再次调用,标示flag为数组长度时代表结果长度已符合要求,也即所有元素都被加入,此时输出。和N-QUEENS的那很像。backtracking应该都是这思路吧。
public class Solution { public List<List<Integer>> permute(int[] num) { List<List<Integer>> result = new ArrayList<List<Integer>>(); Boolean[] visited = new Boolean[num.length]; for (int i = 0; i < visited.length; i ++){ visited[i] = false; } DFS(num, 0, result, new LinkedList<Integer>(), visited); return result; } private void DFS(int[] num, int togo, List<List<Integer>> result, List<Integer> current, Boolean[] visited ){ if (togo == visited.length){ result.add(new LinkedList(current)); } else{ for (int i = 0; i < num.length; i ++){ if (visited[i] == false){ current.add(num[i]); visited[i] = true; DFS(num, togo + 1, result, current, visited); current.remove(current.size() - 1); visited[i] = false; } }//for i }//else }// }
运行时间:8ms
Method 3: (来源:http://www.shuatiblog.com/blog/2014/05/14/Permutations/)
Swap。 [ 0 1 2 3 4 5] 一开始start 在0这个位置,然后0,0互换,调用一次,0,1互换调用一次,...,0,5互换,调用一次便是所有结果。当然比如0,1调用之后0已固定,于是对1-5再一次前述过程。虽然当flag为数组长度时候直接输出数组,因为数组元素一直被变动。
backtracking妙就妙在用一个固定的数据结构,包括了所有的结果。就如这个方法,最后输出的永远是给定的int[] nums,但是每次递归到输出时,nums中的元素排列都不同。博主菜鸟,理解到这里大概能动为什么每次调用完都要复位,比如method 2中要去除最后一个元素,并且将其置为false;比如swap中swap(int[],i,j)之后调用,调用完之后又要swap(int[],i,j)复原。
public class Solution { public List<List<Integer>> permute(int[] num) { List<List<Integer>> result = new ArrayList<List<Integer>>(); permute(num, 0, result); return result; } void permute(int[] num, int start, List<List<Integer>> result) { if (start >= num.length) { ArrayList<Integer> item = convertArrayToList(num); result.add(item); } for (int j = start; j <= num.length - 1; j++) { swap(num, start, j); permute(num, start + 1, result); swap(num, start, j); } } private ArrayList<Integer> convertArrayToList(int[] num) { ArrayList<Integer> item = new ArrayList<Integer>(); for (int h = 0; h < num.length; h++) { item.add(num[h]); } return item; } private void swap(int[] a, int i, int j) { int temp = a[i]; a[i] = a[j]; a[j] = temp; } }
运行时间:3ms
47. Permutations II
Total Accepted: 62802 TotalSubmissions: 229252 Difficulty: Medium
Given a collection of numbers that might contain duplicates, return all possible unique permutations.
For example,
[1,1,2]have the following unique permutations:
[1,1,2],
[1,2,1],
and
[2,1,1].
Method 1: 博主直接在自己的方法加入了 判断句,判断当前结果中是否已含有当前元素。
public class Solution { // O(n!) for N! permutations, O(?) for checking contains ? public List<List<Integer>> permuteUnique(int[] nums) { List<List<Integer>> res = new ArrayList<List<Integer>>(); if (nums == null) return res; for (int i=0; i<nums.length; i++) { insert(nums[i], res); } return res; } public void insert(int num, List<List<Integer>> res) { int size = res.size(); List<Integer> temp; if (size==0) { temp = new ArrayList<Integer>(); temp.add(num); res.add(temp); }else { for (int j=size-1; j>=0; j--) { temp = res.get(j); int tempSize = temp.size(); for (int k=0; k<=tempSize; k++){ List<Integer> perm = new ArrayList<Integer>(temp); perm.add(k,num); if (!res.contains(perm)) { res.add(perm); } } res.remove(j); } } } }
运行时间:132ms
Method 2: (来源: https://cheonhyangzhang.wordpress.com/2015/09/22/47-leetcode-java-permutations-ii-medium/ )
public class Solution { public List<List<Integer>> permuteUnique(int[] num) { List<List<Integer>> result = new ArrayList<List<Integer>>(); Arrays.sort(num); Boolean[] visited = new Boolean[num.length]; for (int i = 0; i < visited.length; i ++){ visited[i] = false; } DFS(num, 0, result, new LinkedList<Integer>(), visited); return result; } private void DFS(int[] num, int togo, List<List<Integer>> result, List<Integer> current, Boolean[] visited ){ if (togo == visited.length){ result.add(new LinkedList(current)); } else{ for (int i = 0; i < num.length; i ++){ if (visited[i] == false){ if (i > 0 && num[i] == num[i-1] && visited[i-1] == false){ continue;//only insert duplicate element when the previous duplicate element has been inserted } current.add(num[i]); visited[i] = true; DFS(num, togo + 1, result, current, visited); current.remove(current.size() - 1); visited[i] = false; } }//for i }//else }// }
因为该方法本来就用一个数组表示是否访问过,因此去重只用保证第一个重数是否已加入(考虑为整体),后面的数只有当第一个数visit之后(整体加入),才被加入,否则continue跳过。为了实现这个思想,必须先对nums排序。
运行时间:9ms
Method 3: (来源: http://yuanhsh.iteye.com/blog/2201228 )
swap版
public List<List<Integer>> permuteUnique(int[] num) { List<List<Integer>> result = new ArrayList<>(); // Arrays.sort(num); // 原文有sort,运行时间5ms,去掉后仍然accept,4ms permutate(result, num, 0); return result; } public void permutate(List<List<Integer>> result, int[] num, int pos) { if(pos == num.length) { List<Integer> list = new ArrayList<Integer>(); for(int a:num) list.add(a); result.add(list); return; } for(int i=pos; i<num.length; i++) { if(hasDuplicate(num, pos, i)) continue; swap(num, i, pos); permutate(result, num, pos+1); swap(num, i, pos); } } private boolean hasDuplicate(int[] num, int start, int end) { for(int i=start; i<end; i++) { if(num[i] == num[end]) return true; } return false; } private void swap(int[] num, int i, int j) { int tmp = num[i]; num[i] = num[j]; num[j] = tmp; }运行时间:4ms
Method 4: (出处与3相同)
博主的方法是用了ArrayList ,然后判断,contains花去了巨大的时间,此方法直接用HashSet做容器,加快了判断。
但是和3一样,原文的博主两种方法都用了排序,然而两周方法去掉排序都是可以accept的,因为这两种方法并不依赖2种的数组判重,
因此并不需要重数相邻。这里自己也是有些疑惑,欢迎指正。
public class Solution { public List<List<Integer>> permuteUnique(int[] num) { List<List<Integer>> result = new ArrayList<>(); // Arrays.sort(num); //原文有排序,运行时间24ms permutate(result, num, 0); return result; } public void permutate(List<List<Integer>> result, int[] num, int pos) { if(pos == num.length) { List<Integer> list = new ArrayList<Integer>(); for(int a:num) list.add(a); result.add(list); return; } for(int i=pos; i<num.length; i++) { if(hasDuplicate(num, pos, i)) continue; swap(num, i, pos); permutate(result, num, pos+1); swap(num, i, pos); } } private boolean hasDuplicate(int[] num, int start, int end) { for(int i=start; i<end; i++) { if(num[i] == num[end]) return true; } return false; } private void swap(int[] num, int i, int j) { int tmp = num[i]; num[i] = num[j]; num[j] = tmp; } }运行时间:21ms
相关文章推荐
- 浅析 Android 的窗口
- ListView与适配器的一起使用
- 从头认识Spring-3.2 简单的AOP日志实现-需要记录方法的运行时间
- springIOC
- Javascript数据类型
- Sublime Text编辑器使用技巧
- cct软件测试
- cct软件测试
- ListView优化
- PHP之访问修饰符
- PHP动态编译时报错
- 基于OpenWrt的PPTP插件适配Bootstrap
- ListView分页
- cct,web技术
- cct,web技术
- MySQL分表、分区
- Sublime text 3 中Package Control 的安装与使用方法(转自 http://devework.com/sublime-text-3-package-control.html)
- 设计模式(2)---策略模式
- Android适配器
- 音视频的几个基本概念