一起养成写作习惯!这是我参与「掘金日新计划 · 4 月更文挑战」的第8天,点击查看活动详情。
前言
每天一道算法题,死磕算法
题目
给定两个整数 n 和 k,返回范围 [1, n] 中所有可能的 k 个数的组合。
你可以按 任何顺序 返回答案。
示例 1:
输入:n = 4, k = 2
输出:
[
[2,4],
[3,4],
[2,3],
[1,2],
[1,3],
[1,4],
]
分析
这道题目和子集那道题目非常相似,所以我们可以直接把子集的模板拿过来
回溯用于子集/组合的模板
function backTrack(track:number[], nums:number[], start:number, result) {
// 把所有结果都放到结果中
result.push(track.slice());
// start来控制树的生长
for (let i = start; i < nums.length; i++){
track.push(nums[i]);
backTrack(track, nums, i + 1, result);
track.pop();
}
}
而我们这道题目,主要就是加了一个结束条件
题解
function backTrack(track,nums,start,result,k):number[][]{
if(track.length===k){
result.push(track.slice());
return;
}
for(let i=start;i<nums.length;i++){
track.push(nums[i]);
backTrack(track,nums,i+1,result,k);
track.pop();
}
}
function combine(n: number, k: number): number[][] {
let result = [];
let nums = [];
for(let i=1;i<n+1;i++){
nums.push(i);
}
backTrack([],nums,0,result,k);
return result;
};
这个题目很简单,我们再来一道
题目
给你一个整数数组 nums ,其中可能包含重复元素,请你返回该数组所有可能的子集(幂集)。
解集 不能 包含重复的子集。返回的解集中,子集可以按 任意顺序 排列。
示例 1:
输入: nums = [1,2,2]
输出: [[],[1],[1,2],[1,2,2],[2],[2,2]]
分析
这个题目诈一看,感觉用我们上面的模板依然能解,但是请注意审题
题目中说包含重复元素,我们以前做的题目都是不重选不重复的
如果重复了会发生什么呢
[
[], [ 1 ],
[ 1, 2 ], [ 1, 2, 2 ],
[ 1, 2 ], [ 2 ],
[ 2, 2 ], [ 2 ]
]
里面会包含重复的答案,这就是重复元素引起的问题
这种题目我们只要画一个图就明白了
我们想要得到不重复的值,只需要剪去一些树枝就行了
剪去的这些树枝有什么特点呢?
他们和前一列的值不相等才能放入最后的结果中
我们知道我们的模板中start是管行的,i是管列的,所以只需要判断i和i-1是否相等,就能判断出来了
题解
function backTrack(track,nums,start,result){
result.push(track.slice());
for(let i=start;i<nums.length;i++){
// 需要判断i列和i-1列是否相等
// 每一行的第一个值我们是需要的,所以i>start
if(i>start && nums[i]===nums[i-1]){
continue;
}
track.push(nums[i]);
backTrack(track,nums,i+1,result);
track.pop();
}
}
function subsetsWithDup(nums: number[]): number[][] {
let result = [];
backTrack([],nums,0,result);
return result;
};
总结
组合和子集的模板是一样的,各种题型,只是在模板中有一些小变化
这种题目还是要多画图,画图以后会明明白白,根据例子然后判断要如何写判断条件