当前位置: 首页 > news >正文

力扣(组合)

解析 LeetCode 77. 组合:回溯算法的高效实现

一、题目分析

在这里插入图片描述

(一)问题定义

给定整数 nk,返回 [1, n] 中所有长度为 k 的组合,组合内元素无序且不重复。

(二)核心挑战

高效枚举所有符合条件的组合,避免重复和遗漏,同时通过剪枝优化减少不必要的递归。

二、算法思路:回溯 + 剪枝

(一)回溯思想

通过递归遍历所有可能的元素选择:

  1. 选择:从当前起始位置开始,选一个数加入组合。
  2. 递归:基于当前选择,递归处理下一个位置,继续选数。
  3. 回溯:递归返回后,撤销当前选择,尝试其他数。

(二)剪枝优化

在循环中,通过条件 (n - i + 1 + answerMin.size()) >= k 剪枝:

  • n - i + 1 表示当前位置 in 还剩的可选数数量。
  • answerMin.size() 是已选数数量。
  • 若剩余可选数 + 已选数 < k,说明无法凑够 k 个数,直接跳过后续循环。

三、代码解析

class Solution {// 存储当前组合List<Integer> answerMin = new ArrayList<>(); // 存储所有符合条件的组合List<List<Integer>> result = new ArrayList<>(); public List<List<Integer>> combine(int n, int k) {// 从起始位置 1 开始回溯backtracking(n, k, 1); return result;}private void backtracking(int n, int k, int startIndex) {// 终止条件:组合长度达到 kif (answerMin.size() == k) { // 将当前组合加入结果(新建列表避免引用问题)result.add(new ArrayList<>(answerMin)); return;}// 遍历当前层可选的数,i 从 startIndex 开始for (int i = startIndex; // 剪枝:剩余数 + 已选数 >= k 才继续,否则无法凑够 k 个i <= n && (n - i + 1 + answerMin.size()) >= k; i++) { // 选择:将 i 加入当前组合answerMin.add(i); // 递归:处理下一层,起始位置为 i+1backtracking(n, k, i + 1); // 回溯:撤销选择,尝试下一个数answerMin.remove(answerMin.size() - 1); }}
}

(一)流程拆解

  1. 初始化answerMin 存当前组合,result 存所有结果。
  2. 回溯启动:调用 backtracking,从 startIndex = 1 开始。
  3. 终止条件:组合长度达 k 时,将当前组合加入 result
  4. 遍历与剪枝:循环中,通过剪枝条件跳过无法凑够 k 个数的情况;选择数 i 后递归,返回后回溯(移除 i )。
  5. 结果返回result 存储所有组合,作为最终结果。

(二)关键逻辑

  • 剪枝优化:减少不必要的递归,提升效率。例如,n=5, k=3,若已选 1 个数,当前 i=4,剩余数 5-4+1=2,已选 1,2+1=3 刚好满足 k=3,继续;若 i=5,剩余数 11+1=2 < 3,直接跳过。
  • 引用问题result.add(new ArrayList<>(answerMin)) 确保存储的是当前组合的副本,避免后续修改影响结果。

四、复杂度分析

(一)时间复杂度

  • 最坏情况(无剪枝):需枚举所有组合,数量为 C(n,k)C(n, k)C(n,k),每个组合生成时间为 O(k)O(k)O(k),总复杂度 O(k×C(n,k))O(k \times C(n, k))O(k×C(n,k))
  • 剪枝后:减少无效递归,实际复杂度低于最坏情况。

(二)空间复杂度

  • 递归栈深度最多为 kanswerMin 最多存 k 个元素,resultC(n,k)C(n, k)C(n,k) 个组合。
  • 空间复杂度为 O(k+C(n,k))O(k + C(n, k))O(k+C(n,k)),主要受结果存储影响。

通过回溯 + 剪枝高效解决组合枚举问题。回溯实现了所有可能的选择与撤销,剪枝优化减少了无效递归,确保算法在合理时间内运行。

http://www.dtcms.com/a/347500.html

相关文章:

  • 如何解决 pyqt5 程序“长时间运行失效” 问题?
  • React学习(十一)
  • Windows 平台查看端口占用情况并终止进程
  • flink常见问题之非法配置异常
  • leetcode 852 山脉数组的顶峰索引
  • 讲点芯片验证中的统计覆盖率
  • 【URP】[平面阴影]原理与实现
  • 如何使用和优化SQL Server存储过程:全面指南
  • 论文阅读:arxiv 2025 Can You Trick the Grader? Adversarial Persuasion of LLM Judges
  • 【数据分享】地级市对外开放程度(2002-2021)-有缺失值
  • SpringBoot自动装配原理深度解析
  • 【LeetCode 热题 100】300. 最长递增子序列——(解法一)记忆化搜索
  • mmap映射物理内存之四内核cache同步
  • 后台管理系统-14-vue3之tag标签页的实现
  • JEI(Journal of Electronic lmaging)SCI四区期刊
  • TypeScript的接口 (Interfaces)讲解
  • Python 版本与 package 版本兼容性检查方法
  • 定时任务——ElasticJob原理
  • ChipCamp探索系列 -- 4. Intel CPU的十八代微架构
  • 【背诵2025】测试
  • 数据结构与算法——树和二叉树
  • 【科研绘图系列】浮游植物的溶解性有机碳与初级生产力的关系
  • 大麦APP抢票
  • 数据结构 之 【AVL树的简介与部分实现】(部分实现只涉及AVL树的插入问题,包括单旋((右单旋、左单旋))、双旋(左右单旋、右左单旋)等操作)
  • 国家自然科学基金(国自然基金)申请技巧详解
  • materials studio中的两种坐标系
  • 基于RISC-V架构的国产MCU在eVTOL领域的应用研究与挑战分析
  • leetcode(同向双指针 滑动窗口)209.长度最小的子数组 713.乘积小于K的子数组 3.无重复字符的最长子串
  • 随机森林1
  • 12 SQL进阶-锁(8.20)