news 2026/5/1 6:52:31

LeetCode 77/216/22组合型回溯法-组合 / 组合总和 III / 括号生成)

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
LeetCode 77/216/22组合型回溯法-组合 / 组合总和 III / 括号生成)

目录

一、题目 1:组合(LeetCode 77)

题目描述

核心思路

难点 & 重点

Java 实现(带剪枝)

拓展延伸

二、题目 2:组合总和 III(LeetCode 216)

题目描述

核心思路

难点 & 重点

Java 实现(带双重剪枝)

拓展延伸

三、题目 3:括号生成(LeetCode 22)

题目描述

核心思路

难点 & 重点

Java 实现(极简版 + 剪枝)

拓展延伸

四、三题对比(回溯法的共性与差异)

笔记总结


一、题目 1:组合(LeetCode 77)

题目描述

给定两个整数nk,返回范围[1, n]中所有可能的k个数的组合(组合无顺序,元素不重复选)。

核心思路

回溯法(选数 + 剪枝)

  1. current记录当前选择的组合,result存最终结果;
  2. start开始枚举数字(避免重复组合,比如选了 1 就不回头选 0);
  3. 终止条件:current.size() == k,将当前组合加入结果;
  4. 剪枝优化:枚举时限制i的上限为n - (k - current.size()) + 1(剩余数字不够凑k个时直接终止)。

难点 & 重点

  • 难点:避免重复组合(通过start控制枚举起点);
  • 重点:剪枝逻辑(减少无效递归,比如n=4,k=2时,start=1的枚举上限是 3,不用枚举到 4)。

Java 实现(带剪枝)

class Solution { public List<List<Integer>> combine(int n, int k) { List<List<Integer>> result = new ArrayList<>(); List<Integer> current = new ArrayList<>(); if (n < k) return result; // 特殊情况:n不够选k个 backtrack(n, 1, k, current, result); return result; } // start:当前枚举的起始数字;need:还需选的数字个数 private void backtrack(int n, int start, int k, List<Integer> current, List<List<Integer>> result) { // 终止:凑够k个数 if (current.size() == k) { result.add(new ArrayList<>(current)); // 注意new新列表,避免引用污染 return; } int need = k - current.size(); int maxI = n - need + 1; // 剪枝:i的上限 for (int i = start; i <= maxI; i++) { current.add(i); // 选i backtrack(n, i + 1, k, current, result); // 下一个数从i+1开始 current.removeLast(); // 回溯:撤销选i } } }

拓展延伸

  • 类似题目:
    • 子集(LeetCode 78):组合的变种(选任意个数的组合),去掉current.size() == k的终止条件即可;
    • 组合总和(LeetCode 39):允许重复选元素,只需将i+1改为i

二、题目 2:组合总和 III(LeetCode 216)

题目描述

找出所有相加之和为nk个数的组合,满足:仅用数字 1-9、每个数字最多用一次,返回所有有效组合。

核心思路

回溯法(选数 + 和约束 + 剪枝):在 “组合” 题的基础上,增加和的约束

  1. sum记录当前组合的和;
  2. 终止条件:current.size() == ksum == n
  3. 额外剪枝:sum + i > n时直接终止(后续数字更大,和会超)。

难点 & 重点

  • 难点:同时满足 “选 k 个数”“和为 n”“数字 1-9 不重复” 三个约束;
  • 重点:和的剪枝(sum + i > n),避免无效递归。

Java 实现(带双重剪枝)

class Solution { public List<List<Integer>> combinationSum3(int k, int n) { List<List<Integer>> result = new ArrayList<>(); List<Integer> current = new ArrayList<>(); backtrack(k, n, 1, 0, current, result); return result; } // start:枚举起点;sum:当前组合的和 private void backtrack(int k, int target, int start, int sum, List<Integer> current, List<List<Integer>> result) { // 终止:凑够k个数且和为target if (current.size() == k) { if (sum == target) { result.add(new ArrayList<>(current)); } return; } int need = k - current.size(); int maxI = 9 - need + 1; // 剪枝1:剩余数字够凑k个 for (int i = start; i <= maxI; i++) { // 剪枝2:当前和+当前数超过target,后续数更大,直接终止 if (sum + i > target) break; current.add(i); backtrack(k, target, i + 1, sum + i, current, result); current.removeLast(); // 回溯 } } }

拓展延伸

  • 类似题目:
    • 组合总和 II(LeetCode 40):数组有重复元素,需先排序 + 跳过重复元素;
    • 第 k 小的和(LeetCode 373):组合和的 TopK 问题,可结合优先队列优化。

三、题目 3:括号生成(LeetCode 22)

题目描述

给定数字n,生成所有有效的括号组合(左括号数 = 右括号数,任意前缀左括号数≥右括号数)。

核心思路

回溯法(选括号 + 有效性约束):选择分支从 “选数字” 变为 “选左 / 右括号”,通过约束保证有效性:

  1. 左括号数left < n时,可选左括号;
  2. 右括号数right < left时,可选右括号;
  3. 利用字符串不可变性实现自动回溯(不用手动删字符)。

难点 & 重点

  • 难点:有效性约束的转化(左≤n、右≤左);
  • 重点:字符串不可变的自动回溯(简化代码)。

Java 实现(极简版 + 剪枝)

class Solution { public List<String> generateParenthesis(int n) { List<String> result = new ArrayList<>(); backtrack(n, 0, 0, "", result); return result; } // left:已用左括号数;right:已用右括号数;current:当前括号串 private void backtrack(int n, int left, int right, String current, List<String> result) { // 剪枝:提前终止无效分支 int remain = 2 * n - current.length(); // 剩余位置 int diff = left - right; // 左-右的数量差 if (remain < diff || (remain - diff) % 2 != 0) { return; // 剩余位置不够补右括号,或无法成对 } // 终止:凑够n对括号 if (current.length() == 2 * n) { result.add(current); return; } // 选左括号 if (left < n) { backtrack(n, left + 1, right, current + '(', result); } // 选右括号 if (right < left) { backtrack(n, left, right + 1, current + ')', result); } } }

拓展延伸

  • 类似题目:
    • 不同括号类型(LeetCode 20):验证括号有效性(基础);
    • 生成所有有效括号(LeetCode 22 变种):支持{}/[]/(),需用栈记录匹配关系。

四、三题对比(回溯法的共性与差异)

维度组合(77)组合总和 III(216)括号生成(22)
回溯核心选数字(无重复)选数字(无重复 + 和约束)选括号(有效性约束)
选择分支多分支(枚举数字,用 for 循环)多分支(枚举数字,用 for 循环)双分支(选左 / 右括号,用 if 判断)
约束条件选 k 个数、不重复选选 k 个数、和为 n、数字 1-9 不重复左≤n、右≤左、总长度 2n
回溯方式手动 removeLast(List)手动 removeLast(List)自动回溯(字符串不可变)
剪枝策略剩余数字够凑 k 个剩余数字够凑 k 个 + 和不超 target剩余位置够补右括号 + 可成对

笔记总结

这三题是回溯法的经典应用,核心逻辑都是「选分支→递归→回溯」,差异仅在于选择分支的数量约束条件的类型

  • 当选择分支是 “多个候选值”(如选数字),用for循环枚举;
  • 当选择分支是 “固定操作”(如选括号),用if判断;
  • 剪枝的本质是提前终止无效分支,需结合题目的约束条件设计。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/5/1 5:46:37

移动端学术利器:6款AI辅助论文写作APP深度评测

论文AI工具核心对比 工具名称 生成速度 字数上限 特色功能 适用场景 Aibiye 20-30分钟 5万字 多模态模型&#xff0c;全球思维链 学术性论文 Aicheck 20-30分钟 5万字 700学科覆盖&#xff0c;15%查重率 全学科论文初稿 稿易AI论文 3分钟 2万字 匿名访问&…

作者头像 李华
网站建设 2026/4/30 12:12:11

从工具筛选到应用实践:学术写作效率提升手册

工具核心特点速览 工具名称 核心优势 适用场景 数据支撑 aibiye 全流程覆盖降重优化 从开题到答辩的一站式需求 支持20万字长文逻辑连贯 aicheck 院校规范适配模板化输出 国内本硕博论文框架搭建 覆盖90%高校格式要求 秒篇 3分钟文献综述生成 紧急补文献章节 知…

作者头像 李华
网站建设 2026/5/1 5:45:31

如何利用法院培训系统提升职工专业素养?

在当前的职场环境中&#xff0c;法院培训系统与工厂培训系统的有效结合&#xff0c;能够显著提升职工的专业素养。这两种系统通过结构化的课程设置和多元化的学习方式&#xff0c;为职工提供了丰富的知识和实用技能。例如&#xff0c;通过实施案例分析和模拟实操&#xff0c;员…

作者头像 李华
网站建设 2026/4/23 6:26:07

精准无痕降重工具盘点:2025年AI改写利器横向对比(含askpaper/aibiiye)

工具名称 降重效率 专业术语保留 适用场景 特色功能 aibiye ⚡⚡⚡⚡ ⚡⚡⚡⚡⚡ 高重复率论文急救 学术风格优化 aicheck ⚡⚡⚡⚡⚡ ⚡⚡⚡⚡ 紧急降重需求 极速处理 askpaper ⚡⚡⚡⚡ ⚡⚡⚡⚡ 精准降重 逻辑结构保护 秒篇 ⚡⚡⚡ ⚡⚡⚡⚡ 日常降重…

作者头像 李华
网站建设 2026/4/29 2:48:38

C语言标点符号逗号和分号使用区别

最近在看linux的源码&#xff0c;突然想到一个问题&#xff0c;源码中的逗号和分号的区别&#xff0c;什么时候使用逗号&#xff0c;什么时候使用分号。逗号的含义是什么&#xff1f;分号的含义是什么&#xff1f;首先&#xff0c;逗号的含义是停顿&#xff0c;分开&#xff0c…

作者头像 李华