C++刷题常用小技巧 [lambda 表达式和 std::function]

631 阅读2分钟

👉 “Offer 驾到,掘友接招!我正在参与2022春招打卡活动点击查看 活动详情

本文已参与「新人创作礼」活动,一起开启掘金创作之路。

lambda 表达式和 std::function

Lambda是匿名函数的别称。从本质上讲,它们是一种在代码的逻辑位置编写函数(比如回调函数)的简单方法。

  • [capture] : 捕获列表 - 捕捉列表总是出现在Lambda函数的开始处。实际上,[]是Lambda引出符。编译器根据该引出符判断接下来的代码是否是Lambda函数。捕捉列表能够捕捉上下文中的变量以供Lambda函数使用;
  • (parameters) : 参数列表 – 与普通函数的参数列表一致。如果不需要参数传递,则可以连同括号“()”一起省略;
  • {statement} : 函数体 – 内容与普通函数一样,不过除了可以使用参数之外,还可以使用所有捕获的变量。
vector<int> v{1,3,2,4};
std::sort(v.begin(), v.end(), [](int a, int b) { return a > b; });

std::function

std::function 是一个模板化对象,用于存储和调用任何可调用类型,例如函数、对象、lambda 和 std::bind 的结果。

  • Ex1 code:
//调用cmp和lambda都可以完成排序,显然lambda写起来更方便
#include <iostream>   
#include <algorithm>    
#include <vector>       
using namespace std;

bool cmp(int a, int b) { return a < b; }
void output(vector<int>& v) { for(auto val : v) cout << val << " "; cout << endl; }

int main () {
    vector<int> v{1,4,7,2,5,8,9,6,3};
    output(v);
    sort(v.begin(), v.end(), cmp); //调用cmp
    sort(v.begin(), v.end(), [](int a, int b) { return a < b; } ); //lambda表达式  int a, int b 也可以换为auto a, auto b
    output(v);
    return 0;
}
  • Ex2 code:
//lambda 和 function的应用,可以将一些函数直接定义在函数体内,采用引用捕获,可以避免传参
#include <iostream>
#include <functional>
using namespace std;

int main() {
    int a = 3, b = 4;
    //Lambda表达式
    auto check = [](int x, int y) {
        return x >= 0 && x <= 5 and y >= 0 && y <= 5;
    };
    //std::function
    function<bool(int, int)> check_ = [](int x, int y) {
        return x >= 0 && x <= 5 and y >= 0 && y <= 5;
    };
    //避免传参
    auto check__ = [&]() {
        return a >= 0 && a <= 5 and b >= 0 && b <= 5;
    };
    if(check(a, b)) cout << "Y\n";
    else cout << "N\n";
    if(check_(a, b)) cout << "Y\n";
    else cout << "N\n";
    if(check__()) cout << "Y\n";
    else cout << "N\n";
    return 0;
}
//output: Y Y Y

例如在Leetcode上的 437. 路径总和 III

//传统的写法
class Solution {
public:
    unordered_map<int,int> mp;
    int ans;
    int pathSum(TreeNode* root, int sum) {
        if(!root) return 0;
        ans = 0;
        mp[0] = 1;
        dfs(root, sum, 0);
        return ans;
    }
​
    void dfs(TreeNode* root, int sum, int cur){
        if(!root) return;
        cur += root->val;
        if(mp.count(cur - sum)) ans += mp[cur - sum];
        mp[cur]++;
        dfs(root->left, sum, cur);
        dfs(root->right, sum, cur);
        mp[cur]--;
    }
};

可以采用function写起来更简洁:

//采用function的写法
class Solution {
public:
    int pathSum(TreeNode* root, int sum) {
        if(!root) return 0;
        unordered_map<int,int> mp;
        int ans = 0;
        mp[0] = 1;
        //function
        function<void(TreeNode*, int)> dfs = [&](TreeNode* root, int cur) {
            if(!root) return;
            cur += root->val;
            if(mp.count(cur - sum)) ans += mp[cur - sum];
            mp[cur]++;
            dfs(root->left, cur);
            dfs(root->right, cur);
            mp[cur]--;
        };
        
        dfs(root, 0);
        return ans;
    }
};