每日一题~组合总数III

原题链接: 216. 组合总和 III - 力扣(LeetCode)

题目描述:

思路分析:

这是一个组合的问题,所以我们可以使用深度优先搜索(DFS)的方式将所有的情况都列举出来,然后将其中符合条件的情况添加到列表中,最后返回这个列表就可以了。详细步骤如下:

1、准备一个 tmp 列表保存当前集合的数据,用 list 列表保存所有符合条件的列表,用 sum 来记录当前 tmp 列表中的数据之和,用一个 used 数组来记录该数据是否已经被使用

2、使用 DFS 来找到所有组合,当 tmp 的 size = k 时,说明 tmp 已经满了,如果 sum = n,说明这个 tmp 符合条件,但是需要注意的是【1,2,3】和【1,3,2】是属于同一个集合,所以我们还需要进行去重操作,因为我们是从小到大来搜索的,所以【1,2,3】一定在【1,3,2】的前面,去重的时候我们只需要判断 tmp.get(i+1) 是否小于 tmp.get(i) 就可以了,如果 tmp.get(i+1) < tmp.get(i),则说明 list 中已经保存了该情况,直接返回即可

代码示例:

java 复制代码
class Solution {
    // 标记是否使用
    int[] used = new int[10];
    // 记录链表中的数据和
    int sum = 0;
    List<List<Integer>> list = new ArrayList<>();
    LinkedList<Integer> tmp = new LinkedList<>();
    public List<List<Integer>> combinationSum3(int k, int n) {
        // 递归
        dfs(1,k,n);
        return list;
    }
    public void dfs(int x,int k, int n) {
        if(tmp.size() == k) {
            if(sum == n) {
                // 去重操作
                for(int i = 0; i < k-1; i++) {
                    if(i+1 < k && tmp.get(i) > tmp.get(i+1)) {
                        return;
                    }
                }
                list.add(new ArrayList<>(tmp));
            }
            return;
        }
        for(int i = x; i < 10; i++) {
            if(used[i] == 0) {
                tmp.add(i);
                sum += i;
                used[i] = 1;
                dfs(x+1,k,n);
                tmp.removeLast();
                sum -= i;
                used[i] = 0;
            
            }
            
        }
    }
}

可以看出,上述步骤还是比较麻烦的,我们不仅需要找出来 1~9 所有的组合情况,还需要对这些情况进行一下去重操作,这样一来效率就非常低了。如果我们在寻找组合的时候,就进行剪枝,只保存升序的列表例如,【1,2,3】,【1,2,4】,【1,2,5】,......【7,8,9】,这样的话我们就不需要找到所有的组合情况,而且还节省了去重的步骤,相比第一种暴力的解决方法就显得高效了很多。

java 复制代码
class Solution {
    // 标记是否使用
    int[] used = new int[10];
    // 记录链表中的数据和
    int sum = 0;
    List<List<Integer>> list = new ArrayList<>();
    LinkedList<Integer> tmp = new LinkedList<>();
    public List<List<Integer>> combinationSum3(int k, int n) {
        // 递归
        dfs(1,k,n);
        return list;
    }
    public void dfs(int x,int k, int n) {
        if(tmp.size() == k) {
            if(sum == n) list.add(new ArrayList<>(tmp));            
            return;
        }
        for(int i = x; i < 10; i++) {
            if(used[i] == 0) {
                // 剪枝
                if(tmp.size() > 0 && i < tmp.peekLast()) continue;
                tmp.add(i);
                sum += i;
                used[i] = 1;
                dfs(x+1,k,n);
                tmp.removeLast();
                sum -= i;
                used[i] = 0;
            
            }
            
        }
    }
}
相关推荐
神仙别闹23 分钟前
基于C++实现(控制台)应用递推法完成经典型算法的应用
开发语言·c++·算法
Ayanami_Reii25 分钟前
进阶数据结构应用-一个简单的整数问题2(线段树解法)
数据结构·算法·线段树·延迟标记
listhi5201 小时前
基于改进SET的时频分析MATLAB实现
开发语言·算法·matlab
Keep_Trying_Go2 小时前
基于Zero-Shot的目标计数算法详解(Open-world Text-specified Object Counting)
人工智能·pytorch·python·算法·多模态·目标统计
xl.liu2 小时前
零售行业仓库商品数据标记
算法·零售
confiself2 小时前
通义灵码分析ms-swift框架中CHORD算法实现
开发语言·算法·swift
做怪小疯子2 小时前
LeetCode 热题 100——二叉树——二叉树的层序遍历&将有序数组转换为二叉搜索树
算法·leetcode·职场和发展
CoderYanger2 小时前
递归、搜索与回溯-记忆化搜索:38.最长递增子序列
java·算法·leetcode·1024程序员节
xlq223224 小时前
22.多态(下)
开发语言·c++·算法
CoderYanger4 小时前
C.滑动窗口-越短越合法/求最长/最大——2958. 最多 K 个重复元素的最长子数组
java·数据结构·算法·leetcode·哈希算法·1024程序员节