leetcode77
从前n个数中挑两个数
var combine = function(n, k) {
const combineHepler = (n,k,startIndex)=>{
for (let i = startIndex; i <= n-(k-path.length)+1; ++i) { //startIndex开始序列
path.push(i);
combineHepler(n, k, i + 1);
path.pop();
}
if(path.length ==k){//终止条件
result.push([...path])
return
}
}
let result =[];//存所有结果的合集
let path = [];//存1个结果
combineHepler(n,k,1);
return result;
};
1.确定终止条件
2.单层回溯逻辑,确定参数
leetcode 216
var combinationSum3 = function(k, n) {
var combineHepler=function(k,n,sum,startIndex){
if(path.length==k){
if(n===sum) {
result.push([...path]);
return;
}
}
for(let i=startIndex;i<=9;i++){
sum+=i;
path.push(i);
combineHepler(k, n, sum, i+1);
sum-=i;
path.pop();
}
};
let result=[];
let path=[];
combineHepler(k,n,0,1);
return result;
};
leetcode 17
var letterCombinations = function(digits) {
const k=digits.length;
const mapValue=['','','abc','def','ghi','jkl','mno','pqrs','tuv','wxyz']
//两种特殊情况,为0和为1
if(!k) return [];
if(k===1){
return mapValue[digits].split("");
}
var letter=function(n,k,a){
if(k===path.length){
result.push(path.join(""))
return
}
for(var v of mapValue[n[a]]){
path.push(v);
letter(n,k,a+1)
path.pop();
}
}
const result=[],path=[];
letter(digits,k,0)
return result
};
字符串和映射需要注意
leetcode 39
var combinationSum = function(candidates, target) {
const combine = function(candidates,target,sum,startIndex){
if(sum>target) return;
if(sum==target){
res.push([...path])
return;
}
for(let i = startIndex;i<candidates.length;i++){
sum+=candidates[i]
path.push(candidates[i])
combine(candidates,target,sum,i)//因为可以重复,所以这里is i not i+1
sum-=candidates[i]
path.pop()
}
}
let path=[],res=[];
candidates.sort()
combine(candidates,target,0,0);
return res;
};
leetcode 40 组合总结II
/**
* @param {number[]} candidates
* @param {number} target
* @return {number[][]}
*/
//难点在于去除同一树层下的,用used标记,used=true是同一树枝,used=false是同一树层
var combinationSum2 = function(candidates, target) {
let res=[],path=[];
candidates.sort((a, b) => a - b);
let used = new Array(candidates.length).fill(false);
const back = function(candidates,target,sum,startindex,used){
if(sum===target){
res.push([...path])
}
for(let i=startindex;i<candidates.length&&sum+candidates[i]<=target;i++){//sum+candidates[i]<=target剪枝不然会超出时间限制
if(i>0 && candidates[i]==candidates[i-1]&&used[i-1]==false){
continue;
}
sum+=candidates[i]
path.push(candidates[i])
used[i]=true
back(candidates,target,sum,i+1,used);
used[i]=false
path.pop()
sum-=candidates[i];
}
}
back(candidates,target,0,0,used)
return res;
};
还是基于原来的模板,不同的是这里的解集不能包括同样的组合,比如[1,2,5]和[5,1,2]就是一样的,因此就要去除同一树层的数,而保留同一树枝的
注意点:
1.candidates排序,因为是在candidates[i]==candidates[i-1]如果相同的情况下展开
升序candidates.sort((a, b) => a - b);
降序candidates.sort((a, b) =>b - a);
2.used数组初始化,并注意fill(false)
let used = new Array(candidates.length).fill(false);
3.剪枝操作
sum+candidates[i]<=target
必不可少,不然会超时