资讯专栏INFORMATION COLUMN

LeetCode 关于回溯问题的看法

ASCH / 2173人阅读

摘要:回溯算法在算法过程中就是类似于枚举算法,尝试在搜索过程中找到问题的解。

回溯算法( BackTrack )在算法过程中就是类似于枚举算法,尝试在搜索过程中找到问题的解。
使用回溯算法解题的一般步骤

使用回溯算法解题的一般步骤:

针对所给问题得出一般的解空间

用回溯搜索方法搜索解空间

使用深度优先去搜索所有解并包含适当的剪枝操作

LeetCode 使用回溯算法的题目主要有 36 题,代表性有 N Queens(51,52), SubSets(78), Permutation(46(distinct), 47(with duplicates)), Combination, Combination Sum.

Problems

SubSets:

Given a set of distinct integers, nums, return all possible subsets (the power set).

Note: The solution set must not contain duplicate subsets.
For example,
If nums = [1,2,3], a solution is:
[[3],[1],[2],[1,2,3],[1,3],[2,3],[1,2],[]]

SubSets 这道题要求 print 出定长 int array 中所有子集合,使用回溯算法遍历定长 array,然后回溯来选择出所有可能的组合.

针对 backTrack 时间复杂度的分析直接复习结果集的大小有效

Runtime: O(2^n), Space: O(n)

Solution:

public List> subsets(int[] nums) {
    if(nums == null || nums.length == 0) return null;`                
    List> res = new ArrayList>();
    helper(nums, res, 0, new ArrayList<>());
    return res;       
}
    
public void helper(int[] nums, List> res, int index, List temp) {
    //考虑空子集的情况
    res.add(new ArrayList<>(temp));
    for(int i = index; i < nums.length; i++) {
        //每次加下一个index的element
        temp.add(nums[i]);
        //深度优先到下一层
        helper(nums, res, i + 1, temp);
        //backTracking
        temp.remove(temp.size() - 1);
    }
}

针对如果输入数组有重复的元素,但是要求输出的结果没有重复,可以一些去重的方法并注意防止溢出

If nums = [1,2,2], a solution is
[[2],[1],[1,2,2],[2,2],[1,2],[]]

Solution:

public List> subsetsWithDup(int[] nums) {
    if(nums == null || nums.length == 0) return null;
    List> res = new ArrayList>();
    //对input数组进行排序,准备为数组进行去重
    Arrays.sort(nums);
    helper(nums, res, 0, new ArrayList<>());
    return res;
}
    
public void helper(int[] nums, List> res, int index, List temp) {
    res.add(new ArrayList<>(temp));
    for(int i = index; i < nums.length; i++) {
        //去重复,并且防止溢出
        if(i != index && nums[i] == nums[i - 1]) continue;
        temp.add(nums[i]);
        helper(nums, res, i + 1, temp);
        temp.remove(temp.size() - 1);
    }
}
Combination Sum

Given a set of candidate numbers (C) (without duplicates) and a target number (T), find all unique combinations in C where the candidate numbers sums to T.

The same repeated number may be chosen from C unlimited number of times.

Note:
All numbers (including target) will be positive integers.
The solution set must not contain duplicate combinations.

For example, given candidate set [2, 3, 6, 7] and target 7, A solution set is:
[[7],[2, 2, 3]]

这道题要求given一个定长数组,要求找到所有子数组集合以至于子数组所有数的和等于目标数,可以运用回溯算法,区间为given的定长数组

Solution:

同样是用回溯的方法,但是针对数组中子数可以重复使用
time:O(2^n), space: O(n)

public List> combinationSum(int[] candidates, int target) {
    if(candidates == null || candidates.length == 0) return null;
    List> res = new ArrayList>();
    helper(candidates, target, res, new ArrayList(), 0);
    return res;
}

public void helper(int[] candidates, int target, List>res, List temp, int index) {
    if(target < 0) return;
    else if(taget == 0) res.add(new ArrayList(temp));
    else {
        for(int i = index; i < candidats.length; i++) {
        temp.add(candidates[i]);
        //DFS dive into next level, 因为需要重复使用所以递归调用i 没有变化
        helper(candidates, target - candidates[i], res, temp, i);
        temp.remove(temp.size() - 1);
    }
}

变种,针对CombinationSum 数组中子数只可以被使用一次:
时间复杂度仍然为O(2^n), 空间复杂度为O(n)

public List> combinationSum(int[] candidates, int target) {
    if(candidates == null || candidates.length == 0) return null;
    List> res = new ArrayList>();
    helper(candidates, target, res, new ArrayList(), 0);
    return res;
}

public void helper(int[] candidates, int target, List>res, List temp, int index) {
        if(target < 0) return;
        else if(taget == 0) res.add(new ArrayList(temp));
        else {
            for(int i = index; i < candidats.length; i++) {
                //进行防溢出和去重
                if(i != index && candidates[i] == candidates[i - 1]) continue;
                temp.add(candidates[i]);
                //DFS dive into next level, 因为需要重复使用所以递归调用i 没有变化
                helper(candidates, target - candidates[i], res, temp, i);
                temp.remove(temp.size() - 1);
    }
}

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/68275.html

相关文章

  • 回溯算法讲解--适用于leetcode绝大多数回溯题目

    摘要:什么是回溯算法回溯法是一种系统搜索问题解空间的方法。解空间定义为与数字长度相同。最后,为什么要掌握回溯法因为懂了回溯法之后笔试里的很多题就算不了,起码成功运行到之间是没问题的。 什么是回溯算法?回溯法是一种系统搜索问题解空间的方法。为了实现回溯,需要给问题定义一个解空间。说到底它是一种搜索算法。只是这里的搜索是在一个叫做解空间的地方搜索。而往往所谓的dfs,bfs都是在图或者树这种数据...

    saucxs 评论0 收藏0
  • LeetCode偶尔一题 —— 39. Combination Sum(回溯算法系列)

    摘要:输入输出分析题目由于我们需要找到多个组合,简单的使用循环肯定是不行的,这时候我们可以使用回溯算法来解决这个问题。用回溯算法解决问题的一般步骤针对所给问题,定义问题的解空间,它至少包含问题的一个最优解。 题目描述 Given a set of candidate numbers (candidates) (without duplicates) and a target number ...

    linkin 评论0 收藏0
  • LeetCode 刷题 (九)算法入门--回溯

    摘要:用来存放每一个可能的结果最终结果深度优先遍历剪枝当遍历到底个数是,如果的元素个数剩余元素个数时,就不满足条件了中元素个数达到,表示深度优先遍历到达最深处了。  77. 组合77. 组合77. 组合 给定两个整数 n 和 k,返回范围 [1, n] 中所有可能的 k 个数的组合。 你可以按 任...

    morgan 评论0 收藏0

发表评论

0条评论

ASCH

|高级讲师

TA的文章

阅读更多
最新活动
阅读需要支付1元查看
<