Leetcode 39.组合总和
题目:39.组合总和
初始思路
和77.组合的区别在于,这里的元素可以重复使用,所以递归退出的条件就不能是个数。只能通过sum和target的关系判断。
代码
var combinationSum = function (candidates, target) {let res = []let path = []// 从小到大排序candidates.sort((a, b) => a - b)const backtracking = (startIndex, sum) => {if (sum === target) {res.push([...path])return}for (let i = startIndex; i < candidates.length; i++){const n = candidates[i]// 如果和大于target就终止遍历if (n + sum > target) breakpath.push(n)sum += nbacktracking(i, sum)// 回溯path.pop()sum -= n}}backtracking(0, 0)return res};
感想
- 图示

- 主要要看懂回溯操作,相比较77更改了一些条件。有startIndex就会排除已经选取过的元素。
Leetcode 40.组合总和 II
题目:40.组合总和 II
初始思路
跟上一题比较,这题每个数字只能重复一次,但是给的数组里面元素是有重复的。也就是说每个解的内部是可以由重复元素的(次数最多和原数组一样)
代码
var combinationSum2 = function (candidates, target) {let res = []let path = []let sum = 0const len = candidates.length// 从小到大排序candidates.sort((a, b) => a - b)// 标记数组let used = new Array(len).fill(false)const backtracking = (startIndex) => {if (sum === target) {res.push([...path])return}for (let i = startIndex; i < len && sum < target; i++){const n = candidates[i]// 如果n === candidates[i - 1]说明和前一个元素重复了,检查一下used数组,如果是false说明同一层candidates[i-1]使用过if (n + sum > target || (i > 0 && n === candidates[i - 1] && !used[i - 1])) continuepath.push(n)sum += nused[i] = truebacktracking(i + 1)// 回溯path.pop()sum -= nused[i] = false}}backtracking(0)return res};
var combinationSum2 = function (candidates, target) {let res = []let path = []let sum = 0const len = candidates.length// 从小到大排序candidates.sort((a, b) => a - b)// 标记数组const backtracking = (startIndex) => {if (sum === target) {res.push([...path])return}for (let i = startIndex; i < len; i++) {const n = candidates[i]if (i > startIndex && candidates[i] === candidates[i - 1]) {//若当前元素和前一个元素相等//则本次循环结束,防止出现重复组合continue}//如果当前元素值大于目标值-总和的值//由于数组已排序,那么该元素之后的元素必定不满足条件//直接终止当前层的递归if (n + sum > target) breakpath.push(n)sum += nbacktracking(i + 1)// 回溯path.pop()sum -= n}}backtracking(0)return res};
感想
- 回看一下题目,元素在同一个组合内是可以重复的,怎么重复都没事,但两个组合不能相同。
- 所以我们要去重的是同一树层上的“使用过”,同一树枝上的都是一个组合里的元素,不用去重。
- 图示

Leetcode 131.分割回文串
题目:131.分割回文串
初始思路
代码
const isPalindrome = (str, left, right) => {for (let i = left, j = right; i < j; i++, j--) {if (str[i] !== str[j]) return false}return true}var partition = function (s) {let res = []let path = []const len = s.lengthconst backtracking = (startIndex) => {if (startIndex >= len) {res.push([...path])return}for (let i = startIndex; i < len; i++) {if (!isPalindrome(s, startIndex, i)) continue// 截取这段字符串,注意左闭右开path.push(s.slice(startIndex, i + 1))// 因为不能重复,所以+1backtracking(i + 1)// 回溯path.pop()}}backtracking(0)return res};
感想
- 具体来说, 给定一个字符串s, 长度为n, 它成为回文字串的充分必要条件是s[0] == s[n-1]且s[1:n-1]是回文字串。
- 好难!

