回溯算法中组合问题的去重通用方案

本文探讨了LeetCode题目90中如何避免子集组合的重复问题,通过介绍使用标记数组(used)在树层遍历中的应用,展示了如何在backtracing函数中正确地进行去重。重点在于理解标记数组的放置位置及其在回溯过程中的作用。
摘要由CSDN通过智能技术生成

求目标数组的组合问题中,很令人头疼的就是去重。

可以举LeetCode90这个经典例子来做说明:

该题要求输出给定数组的所有可能子集,注意解中不能包含重复子集。

该题给的测试用例为[1,2,2]。

很明显如果我们用暴力循环的方式进行求解时会出现两个[1,2]子集,尽管两个2的下标不同,但这是不被允许的。这里可能会有人想到用完一个数后就标记该数,后续遇到该数时就跳过,这种思路是正确的,但牵扯到这个标记是放在树枝遍历还是树层遍历中。附:关于树枝遍历与树层遍历,可以看Carl哥在代码随想录中的总结。🔗

这里我们给出一个通用的解决方案,底层思路就是将这个标记数组放在树层遍历中,熟悉回溯算法的同学应当知道树层遍历发生在backtracing函数的for循环之外,因此该数组定义在for循环之外即可。

    let backtracing = (startIndex) =>{
        res.push([...path])
        if(startIndex === nums.length) return ;
        let used = []; //此处为标记数组的定义
        for(let i = startIndex;i<nums.length;i++){
            if(i >0 && candidates[i] === candidates[i-1] && used[candidates[i] + 10] ) continue;
            path.push(candidates[i]);
            used[candidates[i] + 10]  = true;
            backtracing(i+1);
            path.pop()
        }
    }

注:代码段为LeetCode90中的部分代码段,读者关注used数组的定义位置和判断规则即可。

因为该数组只定义在该层的backtracing中,回溯三部曲的第三步中不必添加used数组的状态转换,只需要定义后在for循环内添加判断即可。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值