傻瓜式回溯算法,一套代码走天下(子集分割篇)

文章讲述了如何利用回溯算法解决组合、子集和分割问题,通过将这些问题转化为二进制表示,简化了解决过程。作者给出了具体的代码示例,虽然算法看似简单,但展示了其通用性和基础性,适用于初学者理解和实践。
摘要由CSDN通过智能技术生成

       在刷了几十道回溯算法之后,回溯大致可以解决如下几类问题(公认的分类):组合、子集、分割、排列、棋盘问题,其实在我看来分割和子集是同一类问题,就像一份吐司面包,分割是需要切成n份,而组合就是把切好的面包片重新组合,将第一块和第五块放在一起。如果把二进制数当成切吐司的刀,那么所有的问题就变得简单了例如:1011010,1就代表该位置需要切一刀,0就不需要切;

对于分割问题

       只要能够搞明白n位二进制有多少种变换组合,就能够将分割的情况全部考虑到,显然n位二进制有2的n次幂的组合种类,一下就是打印所有组合种类的回溯算法,也是解决子集问题和分割问题的核心:

//将n位的二进制组合全部打印出来
public class allCombine {
    List<Integer> path;
    List<List<Integer>> results;

    public static void main(String[] args) {
        allCombine al = new allCombine();
        al.path=new ArrayList<>();
        al.results= new ArrayList<>();
        al.retuall(3);//暂定有3位
        System.out.println(al.results);
    }
    void retuall(int s){
        if(path.size()==s){
            results.add(new ArrayList<>(path));
            return;
        }
        for (int i = 0; i < 2; i++) {
            path.add(i);
            retuall(s);
            path.remove(path.size()-1);
        }

    }
 }

输出结果:

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

这样就可以拿输出的结果判定需要切割的字符串或数组是否需要在第i位进行切割

例如字符串“abc” 当二进制排序为[0,0,0]就可以代表该字符串一刀不切,

当数组为[1,0,1]就可以将字符串映射为{"a","c"},大概就是这个意思,二进制每一个输出的数组结果都可以映射为对字符串的处理方式;

对于子集问题

无非是把分割后的元素进行组合,就拿力扣的78题做一个演示

代码如下:

class Solution {
    List<List<Integer>> results = new ArrayList<>();
    List<List<Integer>> res = new ArrayList<>();
    List<Integer> path = new ArrayList<>();

    public List<List<Integer>> subsets(int[] nums) {
        int s = nums.length;
        retuall(s, 0);//返回数组位数的二进制所有组合
        for (List<Integer> li : results) {//用每个组合映射出一种答案
            List<Integer> pa = new ArrayList<>();
            for (int i = 0; i < li.size(); i++) {
                if (li.get(i) == 1) {//当二进制组合中某位是1时,数组的响应位置的数字就会被保留
                    pa.add(nums[i]);
                }
            }
           res.add(new ArrayList<>(pa));
        }
        return res;
    }

    void retuall(int s, int index) {
        if (path.size() == s) {
            results.add(new ArrayList<>(path));
            return;
        }
        for (int i = 0; i < 2; i++) {
            path.add(i);
            retuall(s, index - 1);
            path.remove(path.size() - 1);
        }

    }
}

总结:用二进制的所有情况去映射答案是一种很死板的算法,可以说是傻瓜式的解决问题的方式,如果对回溯算法掌握的不行的情况下,或者不考虑效率的情况下,就可以照搬,文章写的食用性不是特别强,这种思想的拓展性应该很强,由于时间问题,暂时没有扩展,后期有时间会重写一篇,如果只想速成的同学,建议多思考阅读几遍,应该也不算难理解。

  • 18
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值