您的位置:首页 > 其它

leetcode题解-78. Subsets && 90. Subsets II

2017-04-18 22:08 281 查看
78,题目:

Given a set of distinct integers, nums, return all possible subsets.

Note: The solution set must not contain duplicate subsets.

For example,
If nums = [1,2,3], a solution is:

[
[3],
[1],
[2],
[1,2,3],
[1,3],
[2,3],
[1,2],
[]
]


首先我们看到数组的子集其实就是长度从0-n的一堆数组,且长度为i的数组就是由长度为i-1的数组添加上一个新的元素获得的。所以我们可以使用下面这种方法来获取其所有的子集:

起始subset集为:[]

添加S0后为:[], [S0]

添加S1后为:[], [S0], [S1], [S0, S1]

添加S2后为:[], [S0], [S1], [S0, S1], [S2], [S0, S2], [S1, S2], [S0, S1, S2]

显然规律为添加Si后,新增的subset为克隆现有的所有subset,并在它们后面都加上Si。代码入下:

public static List<List<Integer>> subsets(int[] nums) {
List<List<Integer>> res = new ArrayList<>();
Arrays.sort(nums);
res.add(new ArrayList<Integer>());

for(int num :nums){
List<List<Integer>> tmp = new ArrayList<>();
for(List<Integer> list : res){
List<Integer> aa = new ArrayList<>(list);
aa.add(num);
tmp.add(aa);
}
res.addAll(tmp);
}

return res;
}


此外我们还可以使用backtracking的方法。

public static List<List<Integer>> subsets1(int[] nums) {
List<List<Integer>> res = new ArrayList<>();
Arrays.sort(nums);
backtrack(res, new ArrayList<>(), nums, 0);
return res;
}

public static void backtrack(List<List<Integer>> res, List<Integer> tmp, int[] nums, int start){
res.add(new ArrayList<>(tmp));
for(int i=start; i<nums.length; i++){
tmp.add(nums[i]);
backtrack(res, tmp, nums, i+1);
tmp.remove(tmp.size()-1);
}
}


90,题目:

Given a collection of integers that might contain duplicates, nums, return all possible subsets.

Note: 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],
[]
]


首先第一种思路与上面相同,使用for-each的方法将自己全部求出,不同的是因为含有重复元素,所以我们应该将其从res中去除。加上一个判断语句即可,代码如下所示:

public List<List<Integer>> subsetsWithDup(int[] nums) {
List<List<Integer>> res = new ArrayList<>();
Arrays.sort(nums);
res.add(new ArrayList<>());
for(int num : nums){
List<List<Integer>> tmp = new ArrayList<>();
for(List<Integer> list : res){
List<Integer> aa = new ArrayList<>(list);
aa.add(num);
if(!res.contains(aa))
tmp.add(aa);
}
res.addAll(tmp);
}
return res;
}


考虑到重复元素,我们可以使用下面的方法来进行改进。这样可以将代码效率从4%提升到35%。主要思路是如果前后两个元素相同则将begin置为size,而不进行操作,否则置零。代码入下:

public List<List<Integer>> subsetsWithDup1(int[] nums) {
Arrays.sort(nums);
List<List<Integer>> result = new ArrayList<>();
result.add(new ArrayList<>());
int begin = 0;
for(int i = 0; i < nums.length; i++){
if(i == 0 || nums[i] != nums[i - 1]) begin = 0;
int size = result.size();
for(int j = begin; j < size; j++){
List<Integer> cur = new ArrayList<>(result.get(j));
cur.add(nums[i]);
result.add(cur);
}
begin = size;
}
return result;
}


此外我们仍然可以使用backtracking的方法,代码如下所示:

public List<List<Integer>> subsetsWithDup2(int[] nums) {
Arrays.sort(nums);
List<List<Integer>> result= new ArrayList<>();
dfs(nums,0,new ArrayList<Integer>(),result);
return result;
}

public void dfs(int[] nums,int index,List<Integer> path,List<List<Integer>> result){
result.add(path);
for(int i=index;i<nums.length;i++){
if(i>index&&nums[i]==nums[i-1]) continue;
List<Integer> nPath= new ArrayList<>(path);
nPath.add(nums[i]);
dfs(nums,i+1,nPath,result);
}
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: