C++二分查找算法:查找和最小的 K 对数字

相关专题

二分查找相关题目

题目

给定两个以 非递减顺序排列 的整数数组 nums1 和 nums2 , 以及一个整数 k 。

定义一对值 (u,v),其中第一个元素来自 nums1,第二个元素来自 nums2 。

请找到和最小的 k 个数对 (u1,v1), (u2,v2) ... (uk,vk) 。

示例 1:

输入: nums1 = [1,7,11], nums2 = [2,4,6], k = 3

输出: [1,2],[1,4],[1,6]

解释: 返回序列中的前 3 对数:

1,2\],\[1,4\],\[1,6\],\[7,2\],\[7,4\],\[11,2\],\[7,6\],\[11,4\],\[11,6

示例 2:

输入: nums1 = [1,1,2], nums2 = [1,2,3], k = 2

输出: [1,1],[1,1]

解释: 返回序列中的前 2 对数:

1,1\],\[1,1\],\[1,2\],\[2,1\],\[1,2\],\[2,2\],\[1,3\],\[1,3\],\[2,3

示例 3:

输入: nums1 = [1,2], nums2 = [3], k = 3

输出: [1,3],[2,3]

解释: 也可能序列中所有的数对都被返回:[1,3],[2,3]
参数范围 :

1 <= nums1.length, nums2.length <= 105

-109 <= nums1[i], nums2[i] <= 109

nums1 和 nums2 均为升序排列

1 <= k <= 104

分析

本题还可以用多路归并。

时间复杂度

O(log(m)*o(n2))+O(k+n1)。m是nums1和nums2的最大值。n1是nums1的长度,n2是nums2的长度。

步骤

一,二分找到和第k小的数对的和right。

二,收集所有和小于right的数对,和等于right的数对只收集llEqualNum 对,GetLessEqualNum(nums1, nums2, right - 1)是少于right的数对数量。

GetLessEqualNum

此函数的作用:求和小于等于iSum数对数量。

std::upper_bound(nums2.begin(), nums2.end(), iSum - n)- nums2.begin(); 是数对(n,?) 之和小于等于iSum的数量。
注意: 返回值可能是1e10,超过int的返回,所以返回值用long long。

和第k小的数对的和

第一个符合以下的要求的iSum(符合要求的最小iSum) ,和小于等于iSum的数对数量大于等于k。

代码

核心代码

cpp 复制代码
class Solution {
public:
	vector<vector<int>> kSmallestPairs(vector<int>& nums1, vector<int>& nums2, int k) {
		int left = nums1[0] + nums2[0] - 1, right = nums1.back() + nums2.back();
		while (right - left > 1)
		{
			const auto mid = left + (right - left) / 2;
			if (GetLessEqualNum(nums1, nums2, mid) >= k)
			{
				right = mid;
			}
			else
			{
				left = mid;
			}
		}
		long long llEqualNum = k - GetLessEqualNum(nums1, nums2, right - 1);
		vector<vector<int>> vRet;
		for (const auto& n : nums1)
		{
			for (const auto n2 : nums2)
			{
				if (n + n2 < right)
				{
					vRet.emplace_back(vector<int>{n, n2});
				}
				else if ((n + n2 == right)&&(llEqualNum))
				{
					llEqualNum--;
					vRet.emplace_back(vector<int>{n, n2});
				}
				else
				{
					break;
				}
			}
		}
		return vRet;
	}
	long long GetLessEqualNum(const vector<int>& nums1, const vector<int>& nums2, int iSum)
	{
		long long llNum = 0;
		for (const auto& n : nums1)
		{
			llNum += std::upper_bound(nums2.begin(), nums2.end(), iSum - n)- nums2.begin();
		}
		return llNum;
	}
};

测试代码

template

void Assert(const T& t1, const T& t2)

{

assert(t1 == t2);

}

template

void Assert(const vector& v1, const vector& v2)

{

if (v1.size() != v2.size())

{

assert(false);

return;

}

for (int i = 0; i < v1.size(); i++)

{

Assert(v1[i], v2[i]);

}

}

int main()

{

vector nums1, nums2;

int k;

vector<vector> res;

{

Solution slu;

nums1 = { -10,-4,0,0,6 }, nums2 = { 3,5,6,7,8,100 };

k = 10;

res = slu.kSmallestPairs(nums1, nums2, k);

Assert(vector<vector>{ { {-10, 3}, { -10,5 }, { -10,6 }, { -10,7 }, { -10,8 }, { -4,3 }, { -4,5 }, { -4,6 }, { 0,3 }, { 0,3 }}}, res);

}

{

Solution slu;

nums1 = { 1,7,11 }, nums2 = { 2,4,6 };

k = 3;

res = slu.kSmallestPairs(nums1,nums2, k);

Assert(vector<vector>{ {1, 2}, { 1,4 }, { 1,6 }}, res);

}

{

Solution slu;

nums1 = { 1,1,2 }, nums2 = { 1,2,3 };

k = 2;

res = slu.kSmallestPairs(nums1, nums2, k);

Assert(vector<vector>{ {1, 1}, { 1,1 }}, res);

}

{

Solution slu;

nums1 = { 1,2 }, nums2 = { 3 };

k = 3;

res = slu.kSmallestPairs(nums1, nums2, k);

Assert(vector<vector>{ {1, 3}, { 2,3 }}, res);

}

复制代码
//CConsole::Out(res);

}

扩展阅读

视频课程

有效学习:明确的目标 及时的反馈 拉伸区(难度合适),可以先学简单的课程,请移步CSDN学院,听白银讲师(也就是鄙人)的讲解。
https://edu.csdn.net/course/detail/38771

如何你想快

速形成战斗了,为老板分忧,请学习C#入职培训、C++入职培训等课程
https://edu.csdn.net/lecturer/6176

相关下载

想高屋建瓴的学习算法,请下载《闻缺陷则喜算法册》doc版
https://download.csdn.net/download/he_zhidan/88348653

洒家想对大家说的话
闻缺陷则喜是一个美好的愿望,早发现问题,早修改问题,给老板节约钱。
墨家名称的来源:有所得以墨记之。
如果程序是一条龙,那算法就是他的是睛

测试环境

操作系统:win7 开发环境: VS2019 C++17

或者 操作系统:win10 开发环境:

VS2022 C++17

相关推荐
dying_man4 分钟前
LeetCode--24.两两交换链表中的结点
算法·leetcode
yours_Gabriel4 分钟前
【力扣】2434.使用机器人打印字典序最小的字符串
算法·leetcode·贪心算法
Dovis(誓平步青云)15 分钟前
探索C++标准模板库(STL):String接口的底层实现(下篇)
开发语言·c++·stl·string
草莓熊Lotso1 小时前
【数据结构初阶】--算法复杂度的深度解析
c语言·开发语言·数据结构·经验分享·笔记·其他·算法
KyollBM1 小时前
【CF】Day75——CF (Div. 2) B (数学 + 贪心) + CF 882 (Div. 2) C (01Trie | 区间最大异或和)
c语言·c++·算法
feiyangqingyun1 小时前
Qt/C++开发监控GB28181系统/取流协议/同时支持udp/tcp被动/tcp主动
c++·qt·udp·gb28181
CV点灯大师1 小时前
C++算法训练营 Day10 栈与队列(1)
c++·redis·算法
GGBondlctrl1 小时前
【leetcode】递归,回溯思想 + 巧妙解法-解决“N皇后”,以及“解数独”题目
算法·leetcode·n皇后·有效的数独·解数独·映射思想·数学思想
武子康2 小时前
大数据-276 Spark MLib - 基础介绍 机器学习算法 Bagging和Boosting区别 GBDT梯度提升树
大数据·人工智能·算法·机器学习·语言模型·spark-ml·boosting
武子康2 小时前
大数据-277 Spark MLib - 基础介绍 机器学习算法 Gradient Boosting GBDT算法原理 高效实现
大数据·人工智能·算法·机器学习·ai·spark-ml·boosting