LeetCode216

LeetCode216

目录


题目描述

找出所有相加之和为 targetk 个数的组合,且满足以下条件:

  • 只使用数字 1 到 9。
  • 每个数字最多使用一次。

返回所有可能的有效组合的列表。组合中不能有相同的组合,组合可以以任何顺序返回。


示例

示例 1

输入:

java 复制代码
k = 3, target = 7

输出:

java 复制代码
[
  [1, 2, 4]
]

解释:

  • 1 + 2 + 4 = 7。
  • 没有其他符合条件的组合。

示例 2

输入:

java 复制代码
k = 3, target = 9

输出:

java 复制代码
[
  [1, 2, 6],
  [1, 3, 5],
  [2, 3, 4]
]

解释:

  • 1 + 2 + 6 = 9。
  • 1 + 3 + 5 = 9。
  • 2 + 3 + 4 = 9。

思路分析

问题核心

我们需要找到所有由 k 个不同数字组成的组合,且这些数字的和为 target。数字的范围是 1 到 9,且每个数字只能使用一次。

思路拆解

  1. 深度优先搜索(DFS)
    • 使用 DFS 遍历所有可能的组合。
  2. 剪枝
    • 如果当前数字大于剩余的目标值 target,则跳过该数字。
  3. 回溯
    • 在 DFS 过程中,使用 stack 记录当前组合,并在回溯时移除最后一个数字。
  4. 终止条件
    • 如果当前组合的长度等于 k 且和为 target,则将其加入结果列表。

代码段

java 复制代码
class Solution {
    public List<List<Integer>> combinationSum3(int k, int target) {
        List<List<Integer>> result = new ArrayList<>(); 
        dfs(1, target, k, new LinkedList<>(), result); 
        return result;
    }

    private static void dfs(int start, int target, int k,
            LinkedList<Integer> stack,
            List<List<Integer>> result) {
        if (target == 0 && stack.size() == k) { 
            result.add(new ArrayList<>(stack));
            return;
        }
        for (int i = start; i <= 9; i++) {
            if (target < i) { 
                continue;
            }
            stack.push(i); 
            dfs(i + 1, target - i, k, stack, result); 
            stack.pop();
        }
    }
}

代码逐行讲解

1. 初始化结果列表

java 复制代码
List<List<Integer>> result = new ArrayList<>();
  • result 用于存储所有符合条件的组合。

2. 调用 DFS

java 复制代码
dfs(1, target, k, new LinkedList<>(), result);
  • 调用 DFS 函数,传入起始数字 1、目标值 target、组合长度 kstack(用于记录当前组合)和结果列表 result

3. DFS 函数

java 复制代码
private static void dfs(int start, int target, int k,
        LinkedList<Integer> stack,
        List<List<Integer>> result) {
  • DFS 函数的定义,用于递归生成组合。

4. 找到一个组合

java 复制代码
if (target == 0 && stack.size() == k) {
    result.add(new ArrayList<>(stack));
    return;
}
  • 如果当前组合的长度等于 k 且和为 target,则将其加入结果列表。

5. 遍历数字 1 到 9

java 复制代码
for (int i = start; i <= 9; i++) {
  • start 开始遍历数字 1 到 9,尝试将其加入当前组合。

6. 剪枝

java 复制代码
if (target < i) {
    continue;
}
  • 如果当前数字大于剩余的目标值 target,则跳过该数字。

7. 加入当前数字

java 复制代码
stack.push(i);
  • 将当前数字加入当前组合。

8. 递归

java 复制代码
dfs(i + 1, target - i, k, stack, result);
  • 递归调用 DFS,继续生成下一个数字的组合。

9. 回溯

java 复制代码
stack.pop();
  • 回溯时移除当前数字,尝试其他可能的组合。

复杂度分析

时间复杂度

  • 组合的数量为 C(9, k),即从 9 个数字中选 k 个数字的组合数。
  • 每次生成一个组合需要 O(k) 的时间。
  • 因此,总时间复杂度为 O(C(9, k) * k)

空间复杂度

  • 需要存储所有组合,空间复杂度为 O(C(9, k) * k)
  • 递归栈的深度为 k,因此额外空间复杂度为 O(k)

总结的知识点

1. 深度优先搜索(DFS)

  • 使用 DFS 遍历所有可能的组合。

2. 剪枝

  • 在 DFS 过程中,通过条件判断跳过无效的搜索路径。

3. 回溯

  • 在 DFS 过程中,使用 stack 记录当前组合,并在回溯时移除最后一个数字。

4. 组合问题

  • 通过限制搜索的起始位置(start 参数),避免生成重复的组合。

整合

java 复制代码
class Solution {
    public List<List<Integer>> combinationSum3(int k, int target) {
        List<List<Integer>> result = new ArrayList<>(); // 结果列表
        dfs(1, target, k, new LinkedList<>(), result); // DFS
        return result;
    }

    private static void dfs(int start, int target, int k,
            LinkedList<Integer> stack,
            List<List<Integer>> result) {
        if (target == 0 && stack.size() == k) { // 找到一个组合
            result.add(new ArrayList<>(stack));
            return;
        }
        // 遍历数字 1 到 9
        for (int i = start; i <= 9; i++) {
            if (target < i) { // 剪枝
                continue;
            }
            stack.push(i); // 加入当前组合
            dfs(i + 1, target - i, k, stack, result); // 递归
            stack.pop(); // 回溯
        }
    }
}

总结

通过 DFS 和回溯,高效地找到所有由 k 个不同数字组成的组合,且这些数字的和为 target

相关推荐
IT猿手16 分钟前
超多目标优化:基于导航变量的多目标粒子群优化算法(NMOPSO)的无人机三维路径规划,MATLAB代码
人工智能·算法·机器学习·matlab·无人机
Erik_LinX25 分钟前
算法日记25:01背包(DFS->记忆化搜索->倒叙DP->顺序DP->空间优化)
算法·深度优先
Alidme32 分钟前
cs106x-lecture14(Autumn 2017)-SPL实现
c++·学习·算法·codestepbystep·cs106x
小王努力学编程33 分钟前
【算法与数据结构】单调队列
数据结构·c++·学习·算法·leetcode
最遥远的瞬间35 分钟前
15-贪心算法
算法·贪心算法
维齐洛波奇特利(male)1 小时前
(动态规划 完全背包 **)leetcode279完全平方数
算法·动态规划
项目申报小狂人3 小时前
改进收敛因子和比例权重的灰狼优化算法【期刊论文完美复现】(Matlab代码实现)
开发语言·算法·matlab
让我们一起加油好吗3 小时前
【排序算法】六大比较类排序算法——插入排序、选择排序、冒泡排序、希尔排序、快速排序、归并排序【详解】
c语言·算法·排序算法
夏末秋也凉3 小时前
力扣-贪心-53 最大子数组和
数据结构·算法·leetcode
liruiqiang054 小时前
机器学习 - 投票感知器
人工智能·算法·机器学习