【算法刷题】—7.19深度优先搜索,回溯解决实际问题

简介: ✨今日算法一题组合总和

✨今日算法一题



由于最近事情变多,每日刷题暂时调整为一题,刷题不一定贪多,但是要刷一题有用一题。


组合总和


文章目录


组合总和


题目描述

思路详解


本题相对比较难,下面是参考官方解答的自我解释。方法:回溯。

首先我们定义三个成员变量这样递归的时候就不用每次都传入了。


  • 我们用dfs(pos,rest) 表示递归的函数,其中pos 表示我们当前递归到了数组 candidates 中的第 \textit{pos}pos 个数,而rest 表示我们还需要选择和为rest 的数放入列表作为一个组合;
  • 对于当前的第 pos 个数,我们有两种方法:选或者不选。如果我们选了这个数,那么我们调用dfs(pos+1,rest−candidates[pos]) 进行递归,注意这里必须满足 rest≥candidates[pos]。如果我们不选这个数,那么我们调用 dfs(pos+1,rest) 进行递归;
  • 在某次递归开始前,如果rest 的值为 0,说明我们找到了一个和为 target 的组合,将其放入答案中。每次调用递归函数前,如果我们选了那个数,就需要将其放入列表的末尾,该列表中存储了我们选的所有数。在回溯时,如果我们选了那个数,就要将其从列表的末尾删除。

为了解决重复的问题,这里采用哈希映射(HashMap)


  • 我们使用一个哈希映射(HashMap)统计数组 candidates 中每个数出现的次数。在统计完成之后,我们将结果放入一个列表 \freq 中,方便后续的递归使用。
  • 列表 freq 的长度即为数组 candidates 中不同数的个数。其中的每一项对应着哈希映射中的一个键值对,即某个数以及它出现的次数。
  • 在递归时,对于当前的第pos 个数,它的值为 freq[pos][0],出现的次数为 freq[pos][1],那么我们可以调用dfs(pos+1,rest−i×freq[pos][0])
  • 即我们选择了这个数 i 次。这里 i 不能大于这个数出现的次数,并且 i×freq[pos][0] 也不能大于 rest。同时,我们需要将 i 个 freq[pos][0] 放入列表中。


代码与结果

class Solution {
    List<int[]> freq = new ArrayList<int[]>();
    List<List<Integer>> ans = new ArrayList<List<Integer>>();
    List<Integer> sequence = new ArrayList<Integer>();
    public List<List<Integer>> combinationSum2(int[] candidates, int target) {
        Arrays.sort(candidates);
        for (int num : candidates) {
            int size = freq.size();
            if (freq.isEmpty() || num != freq.get(size - 1)[0]) {
                freq.add(new int[]{num, 1});
            } else {
                ++freq.get(size - 1)[1];
            }
        }
        dfs(0, target);
        return ans;
    }
    public void dfs(int pos, int rest) {
        if (rest == 0) {
            ans.add(new ArrayList<Integer>(sequence));
            return;
        }
        if (pos == freq.size() || rest < freq.get(pos)[0]) {
            return;
        }
        dfs(pos + 1, rest);
        int most = Math.min(rest / freq.get(pos)[0], freq.get(pos)[1]);
        for (int i = 1; i <= most; ++i) {
            sequence.add(freq.get(pos)[0]);
            dfs(pos + 1, rest - i * freq.get(pos)[0]);
        }
        for (int i = 1; i <= most; ++i) {
            sequence.remove(sequence.size() - 1);
        }
    }
}


✨总结


深度优先算法比较难懂,也比较重要更加多加练习!



相关文章
|
2月前
|
存储 算法 C语言
【数据结构与算法 刷题系列】合并两个有序链表
【数据结构与算法 刷题系列】合并两个有序链表
|
5天前
|
算法
【算法】递归、搜索与回溯——汉诺塔
【算法】递归、搜索与回溯——汉诺塔
|
5天前
|
算法
【算法】递归、搜索与回溯——简介
【算法】递归、搜索与回溯——简介
|
5天前
【刷题记录】最大公因数,最小公倍数(辗转相除法、欧几里得算法)
【刷题记录】最大公因数,最小公倍数(辗转相除法、欧几里得算法)
|
13天前
|
算法 Python
【Leetcode刷题Python】改进的算法,高效求一个数的因子
一个高效的Python函数用于找出一个整数的所有因子,通过仅遍历到该数平方根的范围来优化性能。
22 0
|
2月前
|
机器学习/深度学习 人工智能 算法
回溯算法是怎样的
回溯算法,择优搜索:树的深搜+剪枝
|
2月前
|
算法
【数据结构与算法 刷题系列】求带环链表的入环节点(图文详解)
【数据结构与算法 刷题系列】求带环链表的入环节点(图文详解)
|
2月前
|
算法
【数据结构与算法 刷题系列】判断链表是否有环(图文详解)
【数据结构与算法 刷题系列】判断链表是否有环(图文详解)
|
2月前
|
算法
【数据结构与算法 刷题系列】移除链表元素
【数据结构与算法 刷题系列】移除链表元素
|
2月前
|
存储 算法 C语言
【数据结构与算法 刷题系列】环形链表的约瑟夫问题
【数据结构与算法 刷题系列】环形链表的约瑟夫问题

热门文章

最新文章