题目链接: 组合总和
解题思路: 注意同一个数字可以无限制重复被选取,但组合不能重复,还是老套路,从第一个数开始深度搜索遍历,记录sum,记录path,递归,还原sum,还原path,再往右遍历。
解题代码:
var combinationSum = function(candidates, target) {
let path = [];
let result = [];
let sum = 0;
let backtrenking = function(candidates,target,sum,startIndex){
if(sum > target)return;
if(sum === target){
if(sum === target){
let temp = JSON.parse(JSON.stringify(path));
result.push(temp);
}
return;
}
for(let i = startIndex; i< candidates.length; i++){
sum+=candidates[i];
path.push(candidates[i]);
backtrenking(candidates,target,sum,i);
sum-=candidates[i];
path.pop();
}
}
backtrenking(candidates,target,sum,0);
return result;
};
题目链接: 组合总和II
解题思路: 注意这里candidates 中的每个数字在每个组合中只能使用一次。所以再遍历的过程中我们需要进行去重操作,这里去重有两个概念,一个是树枝去重,一个是树层去重,在树枝去重上需要使用一个used[]做一个标记数组,说到这,我们首先应该对给出的数组进行一个排序操作,然后再进行横向遍历的for循环时首先应该判断前一个与当前元素是否相等,相等了还要判断前面那个元素是否被使用过,如果没有被使用过直接continue,否则就放入path,进入递归操作,为什么要这么处理呢?因为俩个紧挨着的元素如果相同的话,且还不做差别️进行深度优先遍历,这样势必会重复的,因为前面那个元素和现在这个元素是一样的,在深度优先搜索遍历上我们就不需要考虑这个问题,只在广度优先搜索遍历上要考虑,也就是在树枝去重上和树层去重的区别。
解题代码:
var combinationSum2 = function (candidates, target) {
let result = [];
let path = [];
let sum = 0;
let nums = candidates.sort((a, b) => a - b);
let used = new Array(candidates.length).fill(0);
let backTrenking = function (nums, target, sum, startIndex, used) {
if (sum > target) return;
if (sum === target) {
let temp = JSON.parse(JSON.stringify(path));
result.push(temp);
return;
}
for (let i = startIndex; i < nums.length; i++) {
// 去重逻辑 很精妙 前面的相同数值在这一趟没用过,这一趟就不能再用了,因为要用的话必定重复
if (nums[i] === nums[i - 1] && i > 0 && used[i - 1] === 0)continue;
sum += nums[i];
path.push(nums[i]);
used[i]=1;
backTrenking(nums, target, sum, i + 1,used);
sum -= nums[i];
path.pop();
used[i]=0;
}
}
backTrenking(nums, target, sum, 0, used);
return result;
};
题目链接: 分割回文串
解题思路: 此题也可以看作是一个组合的问题,让startIndex抽象成分割线,如果是分割后的字符串的前半部分是回文字符串则加入path,然后进入递归,此时递归的是分割的后半部分字符串,依次类推,这个时候可能就会纳闷呢,我第一次切割的后半部分是回文字符串的话怎么办呢,在哪里处理了不?其实是处理了的,就拿“aab”这个字符串举例子,首先切割的是a,是回文字符串,path给push进去,然后ab这个字符串进入了递归,随后依次加入"a"、“b”,然后再返回到ab处一整个被切割,是吧,在这里就处理了,也就是说,右边的子字符串在下一次遍历的结尾将会被处理。
解题代码:
var isPalindrome = function(s){
let arr = Array.from(s);
let left = 0;
let right = arr.length -1;
while(left < right){
if(arr[left] === arr[right]){
left++;
right--;
}else{
return false;
}
}
return true;
}
var partition = function(s) {
let strArr = Array.from(s);
let path = [];
let result = [];
let backtrenking = function(strArr,startIndex){
if(startIndex >= strArr.length){
let temp = JSON.parse(JSON.stringify(path));
result.push(temp);
return;
}
for(let i = startIndex; i<strArr.length;i++){
if(isPalindrome(strArr.slice(startIndex,i+1))){
path.push(strArr.slice(startIndex,i+1).join(""));
}else continue;
backtrenking(strArr,i+1);
path.pop();
}
}
backtrenking(strArr,0);
return result;
};