Subsets与Permutation这两种题型如果用Recursion的方法来解决,其思路是及其相似的。
Given a set of distinct integers, S, return all possible subsets.
Note:
Elements in a subset must be in non-descending order.The solution set must not contain duplicate subsets.
For example,If S = [1,2,3], a solution is:
[
[3],
[1],
[2],
[1,2,3],
[1,3],
[2,3],
[1,2],
[]
]
这道题是求一个集合的所有子集,对于集合中的每个元素有两种选择,放进集合中和不放进集合中。可以用树型结构表示该过程。
另外,由于递归无法有返回值,每个子集(ArrayList
)在递归过程中可以作为参数加到最后的结果(ArrayList
)中。这种情况在使用Java语言的递归中尤其常见。
public class Solution {
public ArrayList> subsets(int[] num) {
ArrayList> result = new ArrayList>();
if(num == null || num.length == 0) {
return result;
}
ArrayList list = new ArrayList();
Arrays.sort(num);
subsetsHelper(result, list, num, 0);
return result;
}
private void subsetsHelper(ArrayList> result,
ArrayList list, int[] num, int pos) {
result.add(new ArrayList(list));
for (int i = pos; i < num.length; i++) {
list.add(num[i]);
subsetsHelper(result, list, num, i + 1);
list.remove(list.size() - 1);
}
}
}
Given a collection of integers that might contain duplicates, nums, return all possible subsets.
Note:
Elements in a subset must be in non-descending order.The solution set must not contain duplicate subsets.
For example,If nums = [1,2,2], a solution is:
[
[2],
[1],
[1,2,2],
[2,2],
[1,2],
[]
]
Subsets II 与 Subsets I 的区别仅在于集合中存在重复元素。因此,如果使用 Subsets I 的方法就会导致最终的结果集中存在一些重复的子集(注意:集合中的元素之间是没有次序关系的)。
此时在 Subsets I 的解题思路基础上,加一些特殊处理即可。以题干中的例子为例,将集合中的重复元素2特殊处理,在每一次的递归过程中要么取第一个2放进集合,要么所有的2都不选进集合中。
此处仅贴出与第一部分不同,即进行特殊处理的代码。
private void subsetsHelper(ArrayList> result,
...
for (int i = pos; i < num.length; i++) {
if ( i != pos && num[i] == num[i - 1]) {
continue;
}
...
}
}
由于每次递归调用函数时,pos的值会变化,因此是可以把所有重复的2选进集合的,确保了存在2的子集的单一性和正确性。
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].
此题解题思路与上题很像,区别在与此题没有位置关系。换种说法,此题可以解读为给出几个元素,生成这些元素的排列组合,因此元素之间是没有位置关系的。
public class Solution {
public ArrayList> permute(int[] num) {
ArrayList> rst = new ArrayList>();
if (num == null || num.length == 0) {
return rst;
}
ArrayList list = new ArrayList();
helper(rst, list, num);
return rst;
}
public void helper(ArrayList> rst, ArrayList list, int[] num){
if(list.size() == num.length) {
rst.add(new ArrayList(list));
return;
}
for(int i = 0; i
此代码在思路上与 Subsets 相似易于理解且在可以套用在Permutation II上。
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].
主要特殊解决重复问题,与 Subsets II 极为相似。
代码与 Permutation I 一样,主要是下面这段代码解决了重复的问题。
public void helper(ArrayList> rst, ArrayList list, int[] num){
...
for(int i = 0; i
任何递归程序均可写成非递归的形式,一般可以有两种方式改写:使用编码方式、使用栈(最常用)。如果一个程序使用非递归形式易懂,那么应该使用非递归形式,因为递归形式毕竟有调用程序的开销。这里给出编码方式解决 Subsets I 的代码。
class Solution {
public ArrayList> subsets(int[] nums) {
ArrayList> result = new ArrayList>();
int n = nums.length;
Arrays.sort(nums);
// 1 << n is 2^n
// each subset equals to an binary integer between 0 .. 2^n - 1
// 0 -> 000 -> []
// 1 -> 001 -> [1]
// 2 -> 010 -> [2]
// ..
// 7 -> 111 -> [1,2,3]
for (int i = 0; i < (1 << n); i++) {
ArrayList subset = new ArrayList();
for (int j = 0; j < n; j++) {
// check whether the jth digit in i's binary representation is 1
if ((i & (1 << j)) != 0) {
subset.add(nums[j]);
}
}
result.add(subset);
}
return result;
}
}
相似题型(后续补充)