78. 子集
1.题目分析
采用回溯算法,注意在backTrack()函数中,进行回溯时必须传入i+1,而不是index+1,因为没有涉及元素的顺序问题,因为在子集中,[1,2]和[2,1]是一样的
2.代码
class Solution {
List<List<Integer>> res;
public List<List<Integer>> subsets(int[] nums) {
res = new ArrayList<>();
List<Integer> list = new ArrayList<>();
backTrack(list,nums,0);
return res;
}
public void backTrack(List<Integer> list, int[] nums, int index){
res.add(new ArrayList<>(list));
回溯终止
if (index >= nums.length)
return;
选择列表
for (int i = index; i < nums.length; i++) {
做选择
list.add(nums[i]);
回溯 跟元素顺序无关,所以是i+1
backTrack(list, nums, i+1);
撤销选择
list.remove((Integer)nums[i]);
}
}
}
46. 全排列
1.题目分析
- 1.相较于前1个题目的子集问题,这个是一个全排列问题,即使元素相同,只要排列顺序不同,也是不一样的;
- 2.使用哈希set来检测是否有重复放置的全排列;
- 3.backTrack()函数中,回溯时传入的是index+1,而不是i+1,是因为涉及到元素顺序的问题,[1,2]和[2,1]是不一样的,跟上一题的相反。
2.代码
class Solution {
存储返回的全排列
List<List<Integer>> res;
检查是否有重复放入的排列
Set<List<Integer>> set;
public List<List<Integer>> permute(int[] nums) {
res = new ArrayList<>();
set = new HashSet<>();
List<Integer> list = new ArrayList<>();
for (int n:nums) {
list.add(n);
}
backTrack(list,0);
return res;
}
public void backTrack(List<Integer> list, int index){
回溯终止
if (index >= list.size())
return;
选择列表
for (int i = index; i < list.size(); i++) {
做选择
Collections.swap(list, index, i);
if (set.add(list))
res.add(new ArrayList<>(list));
回溯,跟元素顺序有关,所以是index+1
backTrack(list,index + 1);
撤销选择
Collections.swap(list, index, i);
}
}
}
77. 组合
1.题目分析
同样使用回溯的大框架,本体相当于从,1 ~ n这n个数中取出k个数组成子集,看有多少种取法。
2.代码
class Solution {
存储返回的全排列
List<List<Integer>> res;
检查是否有重复放入的排列
Set<List<Integer>> set;
public List<List<Integer>> combine(int n, int k) {
res = new ArrayList<>();
set = new HashSet<>();
List<Integer> list = new ArrayList<>();
backTrack(list,n,k,1);
return res;
}
public void backTrack(List<Integer> list, int n, int k, int index){
list存储元素的数量达到k个
if (list.size()==k && set.add(list)){
res.add(new ArrayList<>(list));
return;
}
选择列表
for (int i = index; i <= n; i++) {
做选择
list.add(i);
回溯 跟元素顺序无关,所以是i+1
backTrack(list, n, k, i+1);
撤销选择
list.remove(list.size()-1);
}
}
}