回溯算法双杀:子集 + 电话号码的字母组合 | 经典模板题解析

目录

[一、LeetCode 78:子集](#一、LeetCode 78:子集)

题目描述

核心思路(回溯法)

完整代码

关键解析

[二、LeetCode 17:电话号码的字母组合](#二、LeetCode 17:电话号码的字母组合)

题目描述

核心思路(回溯法)

完整代码

关键解析

三、两道题核心对比

总结


一、LeetCode 78:子集

题目描述

给你一个整数数组 nums,数组中的元素互不相同。返回该数组所有可能的子集(幂集)。解集不能包含重复的子集。

核心思路(回溯法)

子集问题的本质是对每个元素进行「选 / 不选」的决策:

  1. 不选:跳过当前元素,直接处理下一个元素
  2. :将当前元素加入路径,处理完后续元素后再回溯(移除当前元素)

完整代码

java

运行

复制代码
import java.util.ArrayList;
import java.util.List;

public class Solution {
    List<List<Integer>> result = new ArrayList<>();
    List<Integer> path = new ArrayList<>();

    public List<List<Integer>> subsets(int[] nums) {
        backtrack(nums, 0);
        return result;
    }

    private void backtrack(int[] nums, int startIndex) {
        // 每次递归的路径都是一个有效的子集,直接加入结果集
        result.add(new ArrayList<>(path));
        // 遍历从 startIndex 开始的元素,避免重复选择
        for (int i = startIndex; i < nums.length; i++) {
            // 选当前元素
            path.add(nums[i]);
            // 递归处理下一个元素(避免重复,i+1)
            backtrack(nums, i + 1);
            // 回溯:移除当前元素
            path.remove(path.size() - 1);
        }
    }
}

关键解析

  • 递归终止条件:这里没有单独的终止条件,每次递归的路径都是一个有效的子集(包括空集),直接加入结果集即可。
  • 去重逻辑 :通过 startIndex 控制遍历起点,保证每个元素只被选择一次,避免生成重复的子集。

二、LeetCode 17:电话号码的字母组合

题目描述

给定一个仅包含数字 2-9 的字符串 digits,返回所有它能表示的字母组合。答案可以按任意顺序返回。

数字对应的字母映射如下:

  • 2:["a","b","c"]
  • 3:["d","e","f"]
  • 4:["g","h","i"]
  • 5:["j","k","l"]
  • 6:["m","n","o"]
  • 7:["p","q","r","s"]
  • 8:["t","u","v"]
  • 9:["w","x","y","z"]

核心思路(回溯法)

这是典型的组合问题,每个数字对应一组字母,需要按顺序组合不同数字对应的字母:

  1. 用一个哈希表 / 数组保存数字到字母的映射
  2. 递归处理每个数字对应的字母,拼接成完整的组合
  3. 当处理完所有数字时,将拼接好的字符串加入结果集

完整代码

java

运行

复制代码
import java.util.ArrayList;
import java.util.List;

public class Solution {
    // 数字到字母的映射
    private final String[] map = {"", "", "abc", "def", "ghi", "jkl", "mno", "pqrs", "tuv", "wxyz"};
    List<String> result = new ArrayList<>();
    StringBuilder path = new StringBuilder();

    public List<String> letterCombinations(String digits) {
        if (digits == null || digits.length() == 0) {
            return result;
        }
        backtrack(digits, 0);
        return result;
    }

    private void backtrack(String digits, int index) {
        // 处理完所有数字,拼接完成
        if (index == digits.length()) {
            result.add(path.toString());
            return;
        }
        // 获取当前数字对应的字母
        String letters = map[digits.charAt(index) - '0'];
        // 遍历每个字母,尝试拼接
        for (char c : letters.toCharArray()) {
            path.append(c);
            // 处理下一个数字
            backtrack(digits, index + 1);
            // 回溯:移除当前字母
            path.deleteCharAt(path.length() - 1);
        }
    }
}

关键解析

  • 映射处理:用数组直接映射数字到字母,避免哈希表的额外开销,访问更高效。
  • 递归终止条件 :处理完所有数字(index == digits.length()),此时路径拼接完成,加入结果集。
  • 拼接优化 :使用 StringBuilder 代替字符串拼接,减少字符串生成的开销,提升性能。

三、两道题核心对比

表格

题目 核心逻辑 关键技巧 适用场景
子集 每个元素选 / 不选,生成所有可能 startIndex 控制遍历起点,避免重复 无重复元素的幂集生成
电话号码的字母组合 不同数字对应的字母按顺序拼接 数字到字母的映射,按顺序处理每个数字 多组元素的有序组合生成

总结

这两道题是回溯算法的经典入门案例,核心逻辑都是「选择 - 递归 - 回溯」:

  • 子集问题帮助你理解如何处理「每个元素的选 / 不选决策」
  • 电话号码的字母组合帮助你理解「多组元素的有序拼接」
相关推荐
.5482 分钟前
## Sorting(排序算法)
python·算法·排序算法
wuweijianlove27 分钟前
算法的平均复杂度建模与性能回归分析的技术7
算法·数据挖掘·回归
子琦啊31 分钟前
【算法复习】字符串 | 两个底层直觉,吃透高频题
linux·运维·算法
code_pgf2 小时前
Octo 算法详解-开源通用机器人策略模型技术报告
算法·机器人·开源
嘻嘻哈哈樱桃2 小时前
牛客经典101题题解集--动态规划
java·数据结构·python·算法·职场和发展·动态规划
脱氧核糖核酸__2 小时前
LeetCode热题100——234.回文链表(两种解法)
c++·算法·leetcode·链表
IronMurphy2 小时前
【算法四十二】118. 杨辉三角 198. 打家劫舍
算法
电科一班林耿超2 小时前
第 16 课:动态规划专题(二)—— 子序列与子数组问题:面试最高频的 DP 题型
数据结构·算法·动态规划
生信研究猿3 小时前
leetcode 416. 分割等和子集
算法·leetcode·职场和发展
狗哥哥3 小时前
面包屑自动推导的算法设计:从“最短路径匹配”到工程可落地
算法·架构