本文主要为子集,全排列以及组合的题解!带你一文看懂排列组合问题!
子集
给你一个整数数组
nums
,数组中的元素 互不相同 。返回该数组所有可能的子集(幂集)。
解集 不能 包含重复的子集。你可以按 任意顺序 返回解集。
示例 1:
输入:nums = [1,2,3] 输出:[[],[1],[2],[1,2],[3],[1,3],[2,3],[1,2,3]]
看到子集问题第一时间想到的就是回溯,回溯可以避免大量嵌套带来的无用功。
正如我之前所说回溯就是三部曲,递归函数参数,返回值;第二步看终止条件,第三步看单步逻辑
那么这子集问题就非常好解释了,递归函数参数就是给我们的数组还是start值(void backtrack(int[ ] nums,int start)),子集问题就是一字加,没什么终止条件所以不需要判断直接往结果集里面加,就是从头开始track什么都没有的时候加进来一个空集,再向后把1的所有可能加入,再把1去掉从2开始往里加。
class Solution {
List<List<Integer>> res = new LinkedList<>();
LinkedList track = new LinkedList<>();
public List<List<Integer>> subsets(int[] nums) {
backtrack(nums,0);
return res;
}
void backtrack(int[] nums,int start){
res.add(new LinkedList(track));
for(int i =start;i<nums.length;i++){
track.addLast(nums[i]);
backtrack(nums,i+1);
track.removeLast();
}
}
}
77. 组合
给定两个整数
n
和k
,返回范围[1, n]
中所有可能的k
个数的组合。你可以按 任何顺序 返回答案。
示例 1:
输入:n = 4, k = 2 输出: [ [2,4], [3,4], [2,3], [1,2], [1,3], [1,4], ]
这个和子集的区别我觉得就是 给你另一种形式的数组让你把所有的不重复组合写出来。
开始判断三要素:
参数:n和k就是给你的变向数组,还需要有一个值记录你到数组的哪一个值了,所以递归函数就是void backtrack(n,k,start)。
终止条件,k是指k个数,也就是说我的track集合里面有两个数了就要加到res里面了,所以终止条件就是track.size == k。
单层逻辑:排列组合这方面的逻辑都很简单,就是一进一出,start+1就好了。
代码如下
class Solution {
List<List<Integer>> res = new LinkedList<>();
LinkedList<Integer> track = new LinkedList<>();
public List<List<Integer>> combine(int n, int k) {
backtrack(n,k,1);
return res;
}
void backtrack(int n,int k,int start){
if(track.size() == k){
res.add(new LinkedList<>(track));
return;
}
for(int i = start;i<=n;i++){
track.addLast(i);
backtrack(n,k,i+1);
track.removeLast();
}
}
}
是不是有了三部曲就特别轻松了呢!
全排列
给定一个不含重复数字的数组
nums
,返回其 所有可能的全排列 。你可以 按任意顺序 返回答案。示例 1:
输入:nums = [1,2,3] 输出:[[1,2,3],[1,3,2],[2,1,3],[2,3,1],[3,1,2],[3,2,1]]示例 2:
输入:nums = [0,1] 输出:[[0,1],[1,0]]示例 3:
输入:nums = [1] 输出:[[1]]
依旧三部曲
一开始我陷入了误区,以为和组合一样,但是运行的时候发现还有【1,1,1】,【1,2,2】等等,也就是说有重复的啊,那么这个时候就需要维护另一个boolean数组,把这个元素给变成true,撤销变成false,如果true就continue过去。
class Solution {
List<List<Integer>> res = new LinkedList<>();
LinkedList<Integer> track = new LinkedList<>();
public List<List<Integer>> permute(int[] nums) {
boolean[] used = new boolean[nums.length];
backtrack(nums,used);
return res;
}
void backtrack(int[] nums,boolean[] used){
if(track.size() == nums.length){
res.add(new LinkedList(track));
return;
}
for(int i = 0;i<nums.length;i++){
if(used[i]){
continue;
}
track.addLast(nums[i]);
used[i] = true;
backtrack(nums,used);
track.removeLast();
used[i]=false;
}
}
}