【无标题】

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

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

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

/*
22.1.14
寻找两个升序数组组成的(x ,y)最小的k个组合
1.该算法的思想就是每次从已经知道的n个小的组合中估算所有可能出现最小的组合
然后选择出最小的。
2.因为是升序数组,所以假设有(a1,b1)(a2,b2)…(an,bn)那么第n+1个小的就可能是(ai+1,bi)和(ai,bi+1)(i从1-n)
这里的ab都是索引号,明显会出现重复的情况,通过先把(a1~ak,0)放入优先队列,以后每弹出一个最小项就加入一次(ai,bi+1),这样
就不会出现重复。
3.学习了自定义优先队列的使用,包括仿函数,注意优先规则函数的构建是与优先级相反的。
*4.易错点在c++中对应top()函数及时用临时变量保存,因为pop()之后,top()就会发生变化,就不是之前的top().
*/
#include
#include
#include
#include
using namespace std;
class comp
{
public:
int i, j;
int x, y;
bool operator()(comp a, comp b)
{
return (a.x + a.y) > (b.x + b.y);
}
comp(int i,int j,int x,int y)
{
this->i = i;
this->j = j;
this->x = x;
this->y = y;
}
comp()
{
}
};
vector<vector> kSmallestPairs(vector &nums1, vector &nums2, int k);
int main()
{
vectora={1,1,2};
vectorb={1,2,3};
vector<vector>c=kSmallestPairs(a,b,10);
for(int i=0;i<c.size();i++)
cout<<’(’<<c[i][0]<<’,’<<c[i][1]<<’)’;
return 0;
}
vector<vector> kSmallestPairs(vector& nums1, vector& nums2, int k)
{
priority_queue<comp, vector, comp> a;
vector<vector> b;
for (int i = 0; i < nums1.size() && i < k; i++)
{
comp t(i,0,nums1[i],nums2[0]);
a.push(t);
// cout << a.top().x << " " << a.top().y << endl;
}
for (int i = 0; i < k&&!a.empty(); i++)
{
vector t(2);
comp p = a.top();
t[0] = p.x;
t[1] = p.y;
b.push_back(t);
a.pop();
if(p.j + 1<nums2.size())
{
comp t1(p.i, p.j + 1, nums1[p.i], nums2[p.j + 1]);
a.push(t1);
}
}
return b;
}

/*
22.1.14_2
1.核心思想是找一个上限数,这个数可能不会是这两个数组数对的和的值,但是数对和小与这个数的个数大于等于k个,那么输出数对中比该值小的k个数对即可。
2.难点一:统计小于某数数对的个数,注意观察发现两个升序数组进行笛卡尔积形成的矩阵,每行每列都是升序序列,那么在寻找小于某个数的数对时,就可以先依次比较
每行的最后一个元素,因为最后一个元素最大,若小于,那这一行全部都小于,若中间的值小于,那遍历下一行时直接也从这个位置倒退即可,因为这位置之后的
元素一定是大于目标值的。
3.难点二:选择上限数,用折半查找的思路,有2.中的矩阵可知矩阵中的所有数对和一定大于左上角的元素,小于右下角的元素,这便是折半的起点。
4.难点三:有可能小于上限数的个数大于k,但是输出是不按顺序的,所以在输出前k个时有可能并不是最小的k个,所以优先输出小于上限数的,不够的情况下在输出相等的。
5.注意点:数组的小标是从零开始的,所以统计个数时需要+1,对于for循环的条件执行有点误区。
*/
#include
#include
#include
#include
using namespace std;
vector<vector> kSmallestPairs(vector &nums1, vector &nums2, int k);
int main()
{
vectora={1,7,11};
vectorb={2,4,6};
vector<vector>c=kSmallestPairs(a,b,3);
for(int i=0;i<c.size();i++)
cout<<’(’<<c[i][0]<<’,’<<c[i][1]<<’)’;
return 0;
}
vector<vector> kSmallestPairs(vector &nums1, vector &nums2, int k)
{
int n1 = nums1.size(), n2 = nums2.size();
auto count = [&](int t)
{
int star = 0, end = n2 - 1, cnt = 0;
while(star<n1&&end>=0)
{
if(nums1[star]+nums2[end]>t)
end–;
else
{
cnt += end+1;
star++;
}
}
return cnt;
};
int head = nums1[0] + nums2[0], tail = nums1[n1 - 1] + nums2[n2 - 1];
int mid=0, tar = tail;
while (head<=tail)
{
mid = (head + tail) / 2;
if(count(mid)<k)
head=mid+1;
else
{
tar = mid;
tail = mid - 1;
}
}
int end = n2 - 1;
cout << tar;
vector<vector> a;
for (int i = 0; i < n1;i++)//输出小于上限数的
{
while (end>=0&&nums1[i]+nums2[end]>=tar)
end–;
for (int j = 0; j <= end&&a.size() < k;j++)
a.push_back({nums1[i], nums2[j]});
}
end = n2 - 1;
for (int i = 0; i < n1; i++)//输出等于上限数的
{
while (end>=0&&nums1[i]+nums2[end]>tar)
{
end–;
}
//for (int j = 0; j <= end&&a.size() < k&&nums1[i]+nums2[j]==tar;j++)//注意该语句第一次循环就会退出,因为不满足条件了,不会满足了才执行的要注意逻辑
for (int j = 0; j <= end&&a.size() < k;j++)
{
if(nums1[i]+nums2[j]==tar)
a.push_back({nums1[i], nums2[j]});
}
}
return a;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值