m个数 生成n个数的所有组合 详解

news/2024/11/26 17:49:10/

要从给定的 m 个数 中生成 n 个数的所有组合,我们可以使用递归或迭代方法,具体解决过程如下:


1. 问题说明

给定一个大小为 m 的数组,例如 [1, 2, 3],生成所有长度为 n 的组合(可以包括重复数字,也可以不包括)。

两种组合方式:

  1. 组合(不允许重复):

    • 每个数字只能使用一次。
    • 如果 n > m,则没有解。
    • 示例:从 [1, 2, 3] 中选出长度为 2 的组合,结果为:[1, 2], [1, 3], [2, 3]
  2. 带重复的组合(允许重复):

    • 每个数字可以被重复使用。
    • 示例:从 [1, 2, 3] 中选出长度为 2 的组合,结果为:[1, 1], [1, 2], [1, 3], [2, 2], [2, 3], [3, 3]

2. 实现方案

2.1 不允许重复的组合

算法思路
  • 使用递归来构造结果。
  • 每次选择一个数字后,不能再选择它(避免重复)。
  • 当选够了 n 个数字 时,将结果加入最终答案。
实现代码
java">import java.util.ArrayList;
import java.util.List;public class Combinations {public static List<List<Integer>> generateCombinations(int[] nums, int n) {List<List<Integer>> result = new ArrayList<>();backtrack(nums, n, 0, new ArrayList<>(), result);return result;}private static void backtrack(int[] nums, int n, int start, List<Integer> current, List<List<Integer>> result) {// 如果组合长度达到目标 n,添加到结果中if (current.size() == n) {result.add(new ArrayList<>(current));return;}// 从 start 开始,依次选择数字for (int i = start; i < nums.length; i++) {current.add(nums[i]); // 选择当前数字backtrack(nums, n, i + 1, current, result); // 递归选择剩余的数字current.remove(current.size() - 1); // 回溯}}public static void main(String[] args) {int[] nums = {1, 2, 3};int n = 2;List<List<Integer>> combinations = generateCombinations(nums, n);System.out.println(combinations); // 输出: [[1, 2], [1, 3], [2, 3]]}
}
运行流程
  • 假设输入数组为 [1, 2, 3],目标组合长度为 2:
    1. 1 开始,递归选择 23,生成 [1, 2][1, 3]
    2. 2 开始,递归选择 3,生成 [2, 3]
    3. 最终结果为:[[1, 2], [1, 3], [2, 3]]

2.2 允许重复的组合

算法思路
  • 使用递归来构造结果。
  • 每次选择一个数字后,仍然可以选择它(允许重复)。
  • 当选够了 n 个数字 时,将结果加入最终答案。
实现代码
java">import java.util.ArrayList;
import java.util.List;public class CombinationsWithRepetition {public static List<List<Integer>> generateCombinations(int[] nums, int n) {List<List<Integer>> result = new ArrayList<>();backtrack(nums, n, 0, new ArrayList<>(), result);return result;}private static void backtrack(int[] nums, int n, int start, List<Integer> current, List<List<Integer>> result) {// 如果组合长度达到目标 n,添加到结果中if (current.size() == n) {result.add(new ArrayList<>(current));return;}// 从 start 开始,依次选择数字(可以重复选择)for (int i = start; i < nums.length; i++) {current.add(nums[i]); // 选择当前数字backtrack(nums, n, i, current, result); // 递归选择剩余的数字(允许重复)current.remove(current.size() - 1); // 回溯}}public static void main(String[] args) {int[] nums = {1, 2, 3};int n = 2;List<List<Integer>> combinations = generateCombinations(nums, n);System.out.println(combinations); // 输出: [[1, 1], [1, 2], [1, 3], [2, 2], [2, 3], [3, 3]]}
}
运行流程
  • 假设输入数组为 [1, 2, 3],目标组合长度为 2:
    1. 1 开始,递归选择 1, 2, 3,生成 [1, 1], [1, 2], [1, 3]
    2. 2 开始,递归选择 2, 3,生成 [2, 2], [2, 3]
    3. 3 开始,递归选择 3,生成 [3, 3]
    4. 最终结果为:[[1, 1], [1, 2], [1, 3], [2, 2], [2, 3], [3, 3]]

3. 时间复杂度分析

  1. 不允许重复的组合:

    • 假设数组大小为 m,组合长度为 n
    • 时间复杂度为 O ( C ( m , n ) ) = O ( m ! n ! ( m − n ) ! ) O(C(m, n)) = O(\frac{m!}{n!(m-n)!}) O(C(m,n))=O(n!(mn)!m!),因为每种组合只会生成一次。
  2. 允许重复的组合:

    • 时间复杂度为 O ( m n ) O(m^n) O(mn),因为每个位置可以选择 m 种数字,共有 n 个位置。

4. 示例测试

4.1 不允许重复的组合

  • 输入:nums = [1, 2, 3], n = 2
  • 输出:[[1, 2], [1, 3], [2, 3]]

4.2 允许重复的组合

  • 输入:nums = [1, 2, 3], n = 2
  • 输出:[[1, 1], [1, 2], [1, 3], [2, 2], [2, 3], [3, 3]]

5. 总结

特性不允许重复的组合允许重复的组合
是否允许重复选取
时间复杂度 O ( C ( m , n ) ) O(C(m, n)) O(C(m,n)) O ( m n ) O(m^n) O(mn)
适用场景选择独特的对象,避免重复允许重复选择的对象,例如排列、带放回的抽取。

动态规划或递归回溯是生成组合的常见方法,根据问题需求选择适合的实现方式。


http://www.ppmy.cn/news/1550108.html

相关文章

深度学习day4-模型

八 手动构建模型实战 1 构建数据集 epoch&#xff1a;使用训练集的全部数据对模型进行一次完整的训练&#xff0c;被称为一代训练 batch&#xff1a;使用训练集中的部分样本对模型权重进行一次反向传播声望参数更新&#xff0c;这部分样本被称为一批数据 iteration:使用一个…

高质量代理池go_Proxy_Pool

高质量代理池go_Proxy_Pool 声明&#xff01; 学习视频来自B站up主 ​泷羽sec​​ 有兴趣的师傅可以关注一下&#xff0c;如涉及侵权马上删除文章 笔记只是方便各位师傅的学习和探讨&#xff0c;文章所提到的网站以及内容&#xff0c;只做学习交流&#xff0c;其他均与本人以…

2024年11月25日Github流行趋势

项目名称&#xff1a;flux 项目维护者&#xff1a;timudk jenuk apolinario zeke thibautRe项目介绍&#xff1a;FLUX.1模型的官方推理仓库。项目star数&#xff1a;17,381项目fork数&#xff1a;1,229 项目名称&#xff1a;screenshot-to-code 项目维护者&#xff1a;abi cle…

react 中解决 类型“never”上不存在属性“value”。

在 React 中&#xff0c;当你使用 useState 钩子来管理状态时&#xff0c;TypeScript 会尝试推断你的状态变量的类型。在你的例子中&#xff0c;listchannel 被初始化为一个空数组&#xff0c;因此 TypeScript 推断出 listchannel 的类型是 never[]&#xff0c;即一个空数组类型…

ThingsBoard规则链节点:Azure IoT Hub 节点详解

目录 引言 1. Azure IoT Hub 节点简介 2. 节点配置 2.1 基本配置示例 3. 使用场景 3.1 数据传输 3.2 数据分析 3.3 设备管理 4. 实际项目中的应用 4.1 项目背景 4.2 项目需求 4.3 实现步骤 5. 总结 引言 ThingsBoard 是一个开源的物联网平台&#xff0c;提供了设备…

Ubuntu下手动设置Nvidia显卡风扇转速

在Ubuntu下&#xff0c;您可以使用 NVIDIA显卡驱动程序提供的工具手动调整风扇转速。以下是详细步骤&#xff1a; 1. 确保已安装NVIDIA显卡驱动 确保系统已经安装了正确的NVIDIA驱动&#xff1a; nvidia-smi如果没有输出驱动信息&#xff0c;请先安装驱动&#xff1a; sudo…

【FPGA】Verilog:利用 4 个串行输入- 串行输出的 D 触发器实现 Shift_register

0x00 什么是寄存器 寄存器(Register)是顺序逻辑电路中使用的基本组成部分之一。寄存器用于在数字系统中存储和处理数据。寄存器通常由位(bit)构成,每个位可以存储一个0或1的值。通过寄存器,可以设计出计数器、加法器等各种数据处理电路。 0x01 寄存器的种类 基于 D 触发…

一键部署 200+ 开源软件的 Websoft9 面板,Github 2k+ 星星

Websoft9面板是一款基于Web的PaaS/Linux面板&#xff0c;可用于在自己的服务器上一键部署200多种热门开源应用&#xff0c;在Github上获得了2k星星。 特点与优势 丰富的开源软件集成&#xff1a;涵盖数据库、Web服务器、企业建站、电商系统、教育系统、中间件、大数据工具等多…