C++ Lambda表达式

文章介绍了如何使用C++的最小堆和最大堆解决寻找两个递增数组中和最小的k个数对问题。文中详细讲解了lambda表达式的用法,包括其默认返回类型和在优先级队列中的应用。此外,还讨论了关联容器(如map和set)的关键字类型要求以及lambda表达式的局限性,如无法保存内部状态。提供了两种解法的代码实现,一种利用lambda表达式和最小堆,另一种采用自定义比较函数和最大堆。
摘要由CSDN通过智能技术生成

本文原由:

《学习剑指offer——数据结构与算法名企面试题精讲》中:

面试题61:和最小的k个数对
题目:给定两个递增排序的整数数组,从两个数组中各取一个数字u和v组成一个数对(u,v),请找出和最小的k个数对。例如,输入两个数组[1,5,13,21]和[2,4,9,15],和最小的3个数对为(1,2)、(1,4)和(2,5)。

讲解最小堆解法时,用到了lambda表达式,但是C++语法稍有区别,所以重新学习了《C++ Primer》中lambda和关联容器的相关内容。

一个lambda表达式具有如下形式(《C++ Primer》P346):

[capture list] (parameter list) -> return type { function body }

指定lambda返回类型(P353):

        默认情况下,如果一个lambda体包含return之外的任何语句,则编译器假定此lambda返回void。与其他返回void的函数类似,被推断返回void的lambda不能返回值。

关联容器对关键字类型的要求(《C++ Primer》P378):

        对于有序容器——map、multimap、set以及multiset,关键字类型必须定义元素比较的方法。

        传递给排序算法的可调用对象必须满足与关联容器中关键字一样的类型要求。

        所提供的操作必须在关键字类型上定义一个严格弱序。

面试题61:和最小的k个数对

①使用最小堆C++解法代码:

vector<pair<int, int>> kSmallestPairs(const vector<int>& nums1, const vector<int>& nums2, int k)
{
	auto comp = [&nums1, &nums2](const pair<int, int>& left, const pair<int, int>& right)
	{return nums1.at(left.first) + nums2.at(left.second) > nums1.at(right.first) + nums2.at(right.second); };

	priority_queue<pair<int, int>, vector<pair<int, int>>, decltype(comp)> q(comp);
	vector<pair<int, int>> result;

	for (int i = 0; i < k && i < nums1.size(); ++i)
	{
		q.push({ i, 0 });
	}

	while (k-- > 0 && !q.empty())
	{
		pair<int, int> top = q.top();
		result.push_back({ nums1.at(top.first), nums2.at(top.second) });
		q.pop();
		if (top.second < nums2.size() - 1)
			q.push({ top.first, top.second + 1 });
	}

	return result;
}

lambda的局限(《C++标准库 第2版》P232):

        由于priority_queue声明式需要指明lambda类型,所以必须使用decltype,它会为一个lambda对象产出类型。注意,你也必须把lambda对象传入给q的构造函数,否则q会调用被传入的排序准则的default构造函数,而根据C++语言规则,lambda没有default构造函数,也没有assignment操作符。基于这些局限,"以class定义某个函数对象作为排序准则"说不定还比较直观些。

        lambda的另一个问题是,它们无法拥有"跨越多次调用"都能被保存下来的内部状态(internal state)。如果你需要这样的状态,必须在外围作用域中声明一个对象或变量,将它(搭配某种capture)以by_reference方式传入lambda。与此相比,函数对象允许你封装内部状态。

②使用最大堆C++解法代码:

//排序准则
class comparePairSumLess
{
public:
	bool operator()(const pair<int, int>& left, const pair<int, int>& right)
	{
		return left.first + left.second < right.first + right.second;
	}
};

//9_61和最小的k个数对
vector<pair<int, int>> kSmallestPairs(const set<int>& nums1, const set<int>& nums2, int k)
{
	priority_queue <pair<int, int>, vector <pair<int, int>>, comparePairSumLess> q;
	vector<pair<int, int>> result;

	auto cur1 = nums1.begin();
	for (int i = 0; i < k && i < nums1.size(); ++i, ++cur1)
	{
		auto cur2 = nums2.begin();
		for (int j = 0; j < k && j < nums2.size(); ++j, ++cur2)
		{
			int sum = *cur1 + *cur2;
			q.push({ *cur1,*cur2 });
			if (q.size() > k)
			{
				q.pop();
			}
		}
	}

	while (!q.empty())
	{
		result.push_back(q.top());
		q.pop();
	}
	return result;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值