1-回溯算法

回溯算法综述

解决一个回溯问题,实际上就是一个决策树的遍历过程,因此只需要思考如下的三个问题:

  • 路径:已做出的选择

  • 选择列表:可以做的选择

  • 结束条件:已到达决策树的底层,无法再进行选择操作了

代码框架:

result = []

def backtrack(路径, 选择列表)if 满足结束条件:
		result.add(路径)
        return
    for 选择 in 选择列表:
    	做选择
    	backtrack( 路径, 选择列表)
        撤销选择

相当于,在一棵决策树中for循环可以理解是横向遍历,backtracking(递归)就是纵向遍历,这样就把这棵树全遍历完了,一般来说,搜索叶子节点就是找的其中一个结果了。

Tips

Tips

对于for循环选择中,我们是否是要从0开始遍历选择列表,还是要从start开始遍历选择列表

  • 无序:从start开始,如对于[1,2,3]的子集,我们不能回头去取[2,1],这个不是子集。
  • 有序:从0开始,即[a,b]和[b,a]是两个不同列表,是两种不同路径。

对于去重

  • 树枝去重:同一树枝上,表明在同一个track中不能出现重复的,直接先对选择列表去重。

  • 树层去重:同一树层上,在递归函数中,(注意去重需要先对集合排序),我们限制每次填入的字符一定是这个字符所在重复字符集合中「从左往右第一个未被填入的字符」;即满足相邻元素相同,但前一个元素还未使用(隐含着在之前循环已经使用过该元素了)vis[j] || (j > 0 && !vis[j - 1] && s[j - 1] == s[j])

    if (vis[j] || (j > 0 && !vis[j - 1] && arr[j - 1] == arr[j])) {
        continue;
    }
    

例子

leetcode 90. 子集 II

给你一个整数数组 nums ,其中可能包含重复元素,请你返回该数组所有可能的子集(幂集)。

解集 不能 包含重复的子集。返回的解集中,子集可以按 任意顺序 排列。

来源:力扣(LeetCode)
链接:https://leetcode.cn/problems/subsets-ii

输入:nums = [1,2,2]
输出:[[],[1],[1,2],[1,2,2],[2],[2,2]]
class Solution {
    public List<List<Integer>> list;
    public List<List<Integer>> subsetsWithDup(int[] nums) {
        Arrays.sort(nums);
        list  = new LinkedList<>();
        LinkedList<Integer> l = new LinkedList<>();
        int[] flag = new int[nums.length];
        sub(nums, l ,flag, 0);
        return list;
    }
    public void sub(int[] nums, LinkedList<Integer> l , int[] flag, int star){
        list.add(new LinkedList<Integer>(l));
        for(int i = star ; i < nums.length ; i++){
            if( i>0 && flag[i-1] == 0 && nums[i] == nums[i-1]){
                continue;
            }
            l.addLast(nums[i]);
            flag[i] = 1;
            sub(nums, l , flag, i+1);
            l.removeLast();
            flag[i] = 0;
        }
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值