回溯part03
/**
* @param {number[]} candidates
* @param {number} target
* @return {number[][]}
*/
//数组candidates无重复元素
//可以重复选取统一个元素(数字)
//
//注意到元素都是正数,在组合前先排序,方便进行剪支
var combinationSum = function(candidates, target) {
let res = [];
backtracking(target, 0, [], res, candidates, 0);
return res;
};
//迭代的深度是不一定的,因为选择的元素的个数不确定
function backtracking(target, curSum, path, res, candidates, startIndex){
//满足条件
if(curSum === target){
res.push([...path]);
return;
}
//剪枝
if(curSum > target) return;
//选一个数加入
for(let i = startIndex; i < candidates.length; i++){
path.push(candidates[i]);
//由于不能重复,所以每次选择的时候,只能从当前选的数字及以后的数字开始选
backtracking(target, curSum + candidates[i], path, res, candidates, i);
path.pop();
}
}
用一个used数组来判断当前是的树枝还是在数层,然后再来判断是否要选取当前元素
/**
* @param {number[]} candidates
* @param {number} target
* @return {number[][]}
*/
//组合数字,使其和为target,但是每一个数字只能使用一次
var combinationSum2 = function(candidates, target) {
let res = [];
let used = new Array(candidates.length).fill(0);
candidates.sort();
backtracking(candidates, target, 0, [], res, 0, used);
return res;
};
function backtracking(candidates, target, curSum, path ,res, startIndex, used){
//找到满足条件的组合
if(curSum === target){
res.push([...path]);
return;
}
//剪枝
if(curSum > target) return;
for(let i = startIndex; i < candidates.length; i++){
//表示i已经是回溯后的选择
if(i >= 1){
//如果当前元素的值与前面有的元素的值一样,且前面那个值没有正在被使用中,如果正在被使用中的话,那么可能还是在遍历枝条的过程
if(candidates[i - 1] === candidates[i] && !used[i - 1]) continue;
}
//使用candidates[i];
path.push(candidates[i]);
used[i] = 1;
backtracking(candidates, target, curSum + candidates[i], path ,res, i + 1, used);
used[i] = 0;
path.pop();
}
}
怎么去设定参数很重要
如果无法理解,最好自己画个简单案例的树形图
/**
* @param {string} s
* @return {string[][]}
*/
// 首先要判断什么是回文串
// 单个字符一定是回文串
//
var partition = function(s) {
let res = [];
backtracking(0, [], s, res);
return res;
};
//[strStart,strEnd)左开右闭
function backtracking(strStart, path, s, res){
//递归边界,以及切割到字符串的末尾了
if(strStart >= s.length){
res.push([...path]);
return;
}
for(let i = strStart + 1; i <= s.length; i++){
//选取以strStart为开始,i为结束的子串
let subStr = s.slice(strStart, i);
console.log(subStr);
if(!isHuiWen(subStr)) continue;
//是回文子串
path.push(subStr);
backtracking(i, path, s, res);
path.pop();
}
}
function isHuiWen(str){
let st = 0, end = str.length - 1;
while(st <= end){
if(str[st] != str[end]) return false;
st++;
end--;
}
return true;
}