两个有序数组的第K小乘积
Posted 929code
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了两个有序数组的第K小乘积相关的知识,希望对你有一定的参考价值。
给你两个 从小到大排好序 且下标从 0 开始的整数数组 nums1 和 nums2 以及一个整数 k
请你返回第 k (从 1 开始编号)小的 nums1[i] * nums2[j] 的乘积
1. 二分查找
class Solution
public:
typedef long long ll;
long long kthSmallestProduct(vector<int>& nums1, vector<int>& nums2, long long k)
//时间复杂度O(m*n*10glog10)
vector<int> p1,p2,n1,n2;
//将正数负数分开
for(int x:nums1) (x<0)?n1.push_back(x):p1.push_back(x); //n存储负数,p存储正数
for(int x:nums2) (x<0)?n2.push_back(x):p2.push_back(x);
ll l=-1e10,r=1e10; //初始化左右边界
while(l<r)
ll m=(l+r)>>1;
ll cur=0;//计数
//找满足乘积小于等于mid的个数
for(int i=0,j=p2.size()-1;i<p1.size();i++) //正数和正数
while(j>=0&&1LL*p1[i]*p2[j]>m) j--; //指针前移,j及之前的坐标都满足要求,总个数为j+1
cur+=j+1;
for(int i=0,j=0;i<p1.size();i++) //正数和负数
while(j<n2.size()&&1LL*p1[i]*n2[j]<=m) j++; //指针后移,j之前的坐标都满足要求,总个数为j
cur+=j;
for(int i=0,j=n2.size()-1;i<n1.size();i++)//负数和负数
while(j>=0&&1LL*n1[i]*n2[j]<=m) j--; //指针前移,j之后为满足条件的个数,前面有j+1个数,减去
cur+=n2.size()-(j+1); //加上后面的个数
for(int i=0,j=0;i<n1.size();i++)//负数和正数
while(j<p2.size()&&1LL*n1[i]*p2[j]>m) j++; //指针后移,j及之后的为满足条件的个数,前面有j个数,减去
cur+=p2.size()-j;
if(cur<k) l=m+1;//不满足条件
else r=m;
return r;
;
2. 二分 + 二分
优化方法一中对另一个数组的暴力查找
只优化了正数和正数的查找,貌似性能更差,不再继续优化
class Solution
public:
typedef long long ll;
long long kthSmallestProduct(vector<int>& nums1, vector<int>& nums2, long long k)
//时间复杂度O(m*n*10glog10)
vector<int> p1,p2,n1,n2;
//将正数负数分开
for(int x:nums1) (x<0)?n1.push_back(x):p1.push_back(x); //n存储负数,p存储正数
for(int x:nums2) (x<0)?n2.push_back(x):p2.push_back(x);
ll l=-1e10,r=1e10; //初始化左右边界
while(l<r)
ll m=(l+r)>>1;
ll cur=0;//计数
//找满足乘积小于等于mid的个数
for(int i=0,j=p2.size()-1;i<p1.size();i++) //正数和正数
if(p1[i]==0) j = m>=0?p2.size():0;
else
double val = (double)m/p1[i];
auto leftbound = upper_bound(p2.begin(), p2.end(), val);
j = leftbound - p2.begin();
cur+=j;
for(int i=0,j=0;i<p1.size();i++) //正数和负数
while(j<n2.size()&&1LL*p1[i]*n2[j]<=m) j++; //指针后移,j之前的坐标都满足要求,总个数为j
cur+=j;
for(int i=0,j=n2.size()-1;i<n1.size();i++)//负数和负数
while(j>=0&&1LL*n1[i]*n2[j]<=m) j--; //指针前移,j之后为满足条件的个数,前面有j+1个数,减去
cur+=n2.size()-(j+1); //加上后面的个数
for(int i=0,j=0;i<n1.size();i++)//负数和正数
while(j<p2.size()&&1LL*n1[i]*p2[j]>m) j++; //指针后移,j及之后的为满足条件的个数,前面有j个数,减去
cur+=p2.size()-j;
if(cur<k) l=m+1;//不满足条件
else r=m;
return r;
;
数据结构与算法之深入解析“两个有序数组的第K小乘积”的求解思路与算法示例
一、题目要求
- 给你两个从小到大排好序且下标从 0 开始的整数数组 nums1 和 nums2 以及一个整数 k,请你返回第 k(从 1 开始编号)小的 nums1[i] * nums2[j] 的乘积,其中 0 <= i < nums1.length 且 0 <= j < nums2.length。
- 示例 1:
输入:nums1 = [2,5], nums2 = [3,4], k =
以上是关于两个有序数组的第K小乘积的主要内容,如果未能解决你的问题,请参考以下文章
数据结构与算法之深入解析“两个有序数组的第K小乘积”的求解思路与算法示例