• 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。

    代码

    核心代码

    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;
    	}
    };
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49

    测试代码

    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 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{ { {-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{ {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{ {1, 1}, { 1,1 }}, res);
    }
    {
    Solution slu;
    nums1 = { 1,2 }, nums2 = { 3 };
    k = 3;
    res = slu.kSmallestPairs(nums1, nums2, k);
    Assert(vector{ {1, 3}, { 2,3 }}, res);
    }

    //CConsole::Out(res);
    
    • 1

    }

    扩展阅读

    视频课程

    有效学习:明确的目标 及时的反馈 拉伸区(难度合适),可以先学简单的课程,请移步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

  • 相关阅读:
    CSDN常用复杂公式模板记录
    Oracle——行转列与列转行
    Microsemi Libero SoC 教程1 (Libero开发环境)
    参数方程求导
    Domino服务器SSL证书安装指南
    [附源码]计算机毕业设计JAVA实验教学过程管理平台
    Java SPI 二 之 Java APT原理及APT实战 - 一步步教你写ButterKnife
    多旋翼无人机仿真 rotors_simulator:基于PID控制器的位置控制
    Docker技术入门|L1简介及安装
    .NET 8 中的 WPF File Dialog 改进
  • 原文地址:https://blog.csdn.net/he_zhidan/article/details/134476114