代码随想录算法训练营第二十三天 | 39. 组合总和 、40.组合总和II 、131.分割回文串

LeetCode 39. 组合总和

题目链接

视频地址

实现过程:

/**
 * @param {number[]} candidates
 * @param {number} target
 * @return {number[][]}
 */
var combinationSum = function(candidates, target) {
    let path = []
    let res = {}
    let final = []
    backTrack(candidates, target, path, res)
    for(key in res) {
        final.push(res[key])
    }
    return final
};

var backTrack = function(candidates, target, path, res) {
    if(path.reduce((acc,cur) => acc + cur, 0) === target) {
        let newPath = path.slice()
        // 在这里先排序newPath
        newPath.sort()
        const key = JSON.stringify(newPath)
        // 用res对象去重,因为可能存在相同的数组
        if(!res[JSON.stringify(newPath)]) {
            res[key] = newPath
        }
        return
    }
    if(path.reduce((acc,cur) => acc + cur, 0) > target) {
        return
    }
    for(let i=0; i<candidates.length; i++) {
        path.push(candidates[i])
        backTrack(candidates, target, path, res)
        path.pop()
    }
}

学后总结:只要限制下一次选择的起点,是基于本次的选择,这样下一次就不会选到本次选择同层左边的数。即通过控制 for 遍历的起点,去掉会产生重复组合的选项。

/**
 * @param {number[]} candidates
 * @param {number} target
 * @return {number[][]}
 */
var combinationSum = function(candidates, target) {
    let path = []
    let res = []
    var backTrack = function(startIndex) {
        if(path.reduce((acc,cur) => acc + cur, 0) === target) {
            res.push([...path])
            return
        }
        if(path.reduce((acc,cur) => acc + cur, 0) > target) {
            return
        }
        for(let i=startIndex;i<candidates.length;i++) {
            path.push(candidates[i])
            backTrack(i)
            path.pop()
        }
    }
    backTrack(0)
    return res
};

LeetCode 40.组合总和II 

题目链接

视频地址

实现过程:过了98%的用例,但是下面的超时了。

[1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1]

/**
 * @param {number[]} candidates
 * @param {number} target
 * @return {number[][]}
 */
var combinationSum2 = function(candidates, target) {
    let path = []
    let res = {}
    let final = []
    backTrack(candidates, target, path, res, 0)
    for(key in res) {
        final.push(res[key])
    }
    return final
};

var backTrack = function(candidates, target, path, res, startIndex) {
    const sum = path.reduce((acc, cur)=> acc+cur, 0)
    if(sum === target) {
        let newPath = path.slice()
        // 在这里先排序newPath
        newPath.sort()
        const key = JSON.stringify(newPath)
        // 用res对象去重,因为可能存在相同的数组
        if(!res[JSON.stringify(newPath)]) {
            res[key] = newPath
        }
        return
    }
    if(sum > target) {
        return
    }
    for(let i=startIndex; i<candidates.length; i++) {
        path.push(candidates[i])
        backTrack(candidates, target, path, res, i+1)
        path.pop()
    }
};

学后总结:要做树层去重

var combinationSum2 = function(candidates, target) {
    const res = []; path = [], len = candidates.length;
    candidates.sort((a,b)=>a-b);
    backtracking(0, 0);
    return res;
    function backtracking(sum, i) {
        if (sum === target) {
            res.push(Array.from(path));
            return;
        }
        for(let j = i; j < len; j++) {
            const n = candidates[j];
            if(j > i && candidates[j] === candidates[j-1]){
              //若当前元素和前一个元素相等
              //则本次循环结束,防止出现重复组合
              continue;
            }
            //如果当前元素值大于目标值-总和的值
            //由于数组已排序,那么该元素之后的元素必定不满足条件
            //直接终止当前层的递归
            if(n > target - sum) break;
            path.push(n);
            sum += n;
            backtracking(sum, j + 1);
            path.pop();
            sum -= n;
        }
    }
};

LeetCode 131.分割回文串

题目链接

视频地址

学后总结:

/**
 * @param {string} s
 * @return {string[][]}
 */
var partition = function(s) {
    let res = []
    let path = []
    let len = s.length
    var isHw = function(s, start, end) {
        while(start<end) {
            if(s.charAt(start)!==s.charAt(end)){
                return false
            }
            start++
            end--
        }
        return true
    }
    var backTrack = function(startIndex) {
        if(startIndex>=len) {
            res.push(path.slice())
        }
        for(let i = startIndex; i<len; i++) {
            if(isHw(s, startIndex, i)) {
                path.push(s.slice(startIndex, i+1))
                backTrack(i+1)
                path.pop()
            }
        }
    }
    backTrack(0)
    return res
};

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值