39. 组合总和
本题是 集合里元素可以用无数次,那么和组合问题的差别 其实仅在于 startIndex上的控制
题目链接/文章讲解:代码随想录
视频讲解:带你学透回溯算法-组合总和(对应「leetcode」力扣题目:39.组合总和)| 回溯法精讲!_哔哩哔哩_bilibili
根据卡尔的官方视频讲解,来看一下JS代码吧:
/**
* @param {number[]} candidates
* @param {number} target
* @return {number[][]}
*/
// 回溯三部曲:
// 1、函数参数和返回值
// 2、确定终止条件
// 3、单层搜索逻辑
var combinationSum = function(candidates, target) {
// 二维数组,存放结果集
let result = [];
// 一维数组
let path = [];
// path这个数组里面元素的和 = sum
const backtracking = (candidates, target, sum, startIndex) => {
if (sum > target) {
return;
};
if (sum == target) {
result.push(path.slice())
return;
}
for (let i = startIndex;i < candidates.length;i++) {
path.push(candidates[i]);
sum += candidates[i];
// 元素可以重复使用,要保证传进来的为i
backtracking(candidates, target, sum, i);
sum -= candidates[i];
path.pop();
}
}
backtracking(candidates, target, 0, 0)
return result;
};
40.组合总和II
本题开始涉及到一个问题了:去重。
注意题目中给我们 集合是有重复元素的,那么求出来的 组合有可能重复,但题目要求不能有重复组合。
题目链接/文章讲解:代码随想录
视频讲解:回溯算法中的去重,树层去重树枝去重,你弄清楚了没?| LeetCode:40.组合总和II_哔哩哔哩_bilibili
/**
* @param {number[]} candidates
* @param {number} target
* @return {number[][]}
*/
var combinationSum2 = function(candidates, target) {
let res = [];
let path = [];
let total = 0;
const len = candidates.length;
candidates.sort((a, b) => a - b);
let used = new Array(len).fill(false);
const backtracking = (startIndex) => {
if (total === target) {
res.push([...path]);
return;
}
for(let i = startIndex; i < len && total < target; i++) {
const cur = candidates[i];
if (cur > target - total || (i > 0 && cur === candidates[i - 1] && !used[i - 1])) continue;
path.push(cur);
total += cur;
used[i] = true;
backtracking(i + 1);
path.pop();
total -= cur;
used[i] = false;
}
}
backtracking(0);
return res;
};
131.分割回文串
本题较难,大家先看视频来理解 分割问题,明天还会有一道分割问题,先打打基础。
视频讲解:带你学透回溯算法-分割回文串(对应力扣题目:131.分割回文串)| 回溯法精讲!_哔哩哔哩_bilibili
看了卡尔的官方视频讲解,看一下JS代码吧:
/**
* @param {string} s
* @return {string[][]}
*/
// 一个函数,判断是否是回文串,给定一个字符串判断从start到end的区间是否是回文串
const isPalindrome = (s, l, r) => {
for (let i = l, j = r; i < j; i++, j--) {
if(s[i] !== s[j]) return false;
}
return true;
}
var partition = function(s) {
// 一维数组
let path = [];
// 二维数组
let result = [];
const backtracking = (s, startIndex) => {
// 确定终止条件
if (startIndex >= s.length) {
result.push(path.slice())
return;
};
for (let i = startIndex;i< s.length;i++) {
// 判断是否是回文串
if (!isPalindrome(s, startIndex, i)) {
continue;
};
path.push(s.slice(startIndex, i + 1));
backtracking(s, i + 1);
path.pop();
}
}
backtracking(s, 0)
return result;
};