题目描述
小力将 N
个零件的报价存于数组 nums
。小力预算为 target
,假定小力仅购买两个零件,要求购买零件的花费不超过预算,请问他有多少种采购方案。
注意:答案需要以 1e9 + 7 (1000000007)
为底取模,如:计算初始结果为:1000000008
,请返回 1
。
样例
输入:nums = [2,5,3,5], target = 6
输出:1
解释:预算内仅能购买 nums[0] 与 nums[2]。
输入:nums = [2,2,1,9], target = 10
输出:4
解释:符合预算的采购方案如下:
nums[0] + nums[1] = 4
nums[0] + nums[2] = 3
nums[1] + nums[2] = 3
nums[2] + nums[3] = 10
限制
2 <= nums.length <= 10^5
1 <= nums[i], target <= 10^5
算法
(双指针) $O(n \log n)$
- 将数组从小到大排序。
- 对于每个位置 $l$,找到最大的位置 $r$,满足 $nums(l) + nums(r) \le target$,此时 $nums(l)$ 可以与 $r - l$ 个数字组成一个方案。
- 初始时 $l = 0$,$r = n - 1$。注意到 $r$ 是随着 $l$ 的增大而不增的。
时间复杂度
- 排序的时间复杂度为 $O(n \log n)$。
- 排序后,每个位置仅被遍历一次,故总时间复杂度为 $O(n \log n)$。
空间复杂度
- 仅需要常数的额外空间。
C++ 代码
class Solution {
public:
int purchasePlans(vector<int>& nums, int target) {
const int mod = 1000000007;
sort(nums.begin(), nums.end());
const int n = nums.size();
int ans = 0;
int l = 0, r = n - 1;
while (l < r) {
while (l < r && nums[l] + nums[r] > target)
r--;
if (l < r)
ans = (ans + r - l) % mod;
l++;
}
return ans;
}
};