小力将 N 个零件的报价存于数组 nums。小力预算为 target,假定小力仅购买两个零件,要求购买零件的花费不超过预算,请问他有多少种采购方案。
注意:答案需要以 1e9 + 7 (1000000007) 为底取模,如:计算初始结果为:1000000008,请返回 1。
直接二重for循环会超时,即使第二层循环使用二分查找也超时!
int solve(int left,int right,int x,vector<int> nums)
{
while(left<=right)
{
int mid=(left+right)/2;
mid=mid%1000000007;
if(nums[mid]<x)
{
right=mid-1;
}
else if(nums[mid]>x)
{
left=mid+1;
}
else
{
right=mid-1;
}
}
return left;
}
class Solution {
public:
int purchasePlans(vector<int>& nums, int target) {
int len=nums.size();
sort(nums.begin(),nums.end(),greater<int>());
int sum=0;
for(int i=0;i<len;i++)
{
int x=target-nums[i];
int left=solve(i+1,len-1,x,nums);//注意要从i+1开始,防止重复
sum+=(len-left)%1000000007;
sum%=1000000007;
}
return sum;
}
};
所以选择双指针!
首先,为了便于计算,我们先对nums做升序排序。
e.g. nums:[1,2,2,9] target: 10
然后,创建一个指针left,指向 nums首位,再创建一个指针right,指向 nums末尾,然后通过遍历,找到符合 nums[left] + nums[right] <= target条件的left, right区间范围。
既然该范围的边界值之和都满足了条件,那么代表该区间内的所有数字与nums[left]相加都满足条件,所以,我们可以通过right-left来获取到当前有多少个数,可以和 nums[left]相加后满足条件!
i:0 j:3 nums[0] + nums[3] = 10,满足条件 <= 10
所以,当 i = 0 时,存在 j - i = 3 种方案,即:[0,1],[0,2],[0,3]
------------------------------------------------------------
然后 i 指针右移一位,如下所示:
i:1 j:3 nums[1] + nums[3] = 11,不满足条件 <= 10
------------------------------------------------------------
所以 j 指针左移一位,如下所示:
i:1 j:2 nums[1] + nums[2] = 4,满足条件 <= 10
------------------------------------------------------------
所以,当 i = 1 时,存在 j - i = 1 种方案,即:[1,2]
最后,满足条件的方案总共就是 [0,1],[0,2],[0,3],[1,2] 这 4 种方案!
class Solution {
public:
int purchasePlans(vector<int>& nums, int target) {
int len=nums.size();
sort(nums.begin(),nums.end());
int sum=0;
int left=0,right=len-1;
while(left<right)//有没有等于都行,因为就算等了,sum+0=sum
{
if(nums[left]+nums[right]>target)
{
right--;
}
else
{
sum+=(right-left)%1000000007;
sum%=1000000007;
left++;
}
}
return sum;
}
};