c++ lambda表达式原理及应用(以leecode 17为例)

1.lambda表达式格式

[捕获列表](形参列表)mutable 异常列表->返回类型
{
	函数体
}
  • [捕获列表]:定义了Lambda函数体中可以访问哪些​​外部变量​​以及如何访问它们(一般只需值捕获和引用捕获)
  • (形参列表):和不同的传参无区别
  • mutable:需要修改按值捕获变量的内部副本时,使用 mutable
  • 异常列表:声明一个 lambda 表达式(或普通函数)可能抛出哪些类型的异常
  • 正常的函数返回值类型
  • {}正常函数体

2.lambda在递归的应用

LeeCode 17 电话字母组合

lambda在递归的应用
public:
    vector<string> letterCombinations(string digits) {
        int n = digits.length();
        if (n == 0) {
            return {};
        }

        vector<string> ans;
        string path(n, 0); // 注意 path 长度一开始就是 n,不是空串

        // lambda 递归
        auto dfs = [&](this auto&& dfs, int i) -> void {
            if (i == n) {
                ans.emplace_back(path);
                return;
            }
            for (char c : MAPPING[digits[i] - '0']) {
                path[i] = c; // 直接覆盖
                dfs(i + 1);
            }
        };

        dfs(0);
        return ans;
    }
}
auto dfs = [&](this auto&& dfs, int i) -> void {
    // ... 递归逻辑
};
  • ​​[&]​​:这表示Lambda以​​引用方式​​捕获所有外部变量。在函数体内,你可以直接使用和修改外层的 digits、n、ans、path等变量,无需通过参数传递,非常方便。
  • (this auto&& dfs, int i)​​:这是实现递归的核心技巧(C++23标准支持,在C++14及以后也可通过特定编译器扩展使用)。
  • auto&& dfs:这是一个​​模板参数​​,它允许你将Lambda自身作为一个参数传递进来。这样,在函数体内部,你就可以通过 dfs这个名字来​​递归调用自己​​。
  • int i:这是递归的​​核心参数​​,表示当前正在处理电话号码字符串 digits中的第几位数字。
if (i == n) { // 递归终止条件:已经处理完所有数字
    ans.emplace_back(path); // 将当前路径(一个完整的字母组合)加入结果集
    return;
}
for (char c : MAPPING[digits[i] - '0']) { // 遍历当前数字对应的所有字母
    path[i] = c; // 选择:将当前字母填入路径的第 i 个位置
    dfs(i + 1); // 递归:处理下一个数字
    // 注意:这里没有显式的"撤销选择"步骤,因为直接覆盖了 path[i]
}
  • 递归算法第一步需要考虑的便是终止条件,本题中终止条件:当索引 i等于数字字符串的长度 n时,说明已经处理完所有数字,当前 path中存储的就是一个完整的字母组合,将其加入结果集 ans并返回。
  • 遍历与递归​​:对于当前数字 digits[i]所映射的每一个字母 c:
    ​​做出选择​​:将字母 c放入路径 path的第 i个位置。
    ​​递归到下一层​​:调用 dfs(i + 1),处理下一个数字。这一步是递归的关键。
    ​​隐式回溯​​:由于下一层递归调用会​​直接覆盖​​ path[i+1]的位置,而当前层的 path[i]在下次循环时又会被新的字母覆盖,所以这里没有显式的回溯步骤(如 pop_back)。这是一种利用固定长度数组和覆盖操作来避免显式回溯的技巧
Logo

码道开发者社区,聚焦华为云码道 CodeArts 代码智能体,沉淀 Agent、Skill、鸿蒙开发实战内容,供开发者查阅资料、交流技术、分享工程实践

更多推荐