持续创作,加速成长!这是我参与「掘金日新计划 · 10 月更文挑战」的第4天,点击查看活动详情
每日刷题 2022.10.01
- leetcode原题链接:leetcode.cn/problems/4x…
- 难度:简单
题目
- 小力将
N
个零件的报价存于数组nums
。小力预算为target
,假定小力仅购买两个零件,要求购买零件的花费不超过预算,请问他有多少种采购方案。 - 注意:答案需要以
1e9 + 7 (1000000007)
为底取模,如:计算初始结果为:1000000008
,请返回1
示例
- 示例1
输入:`nums = [2,5,3,5], target = 6`
输出:`1`
解释:预算内仅能购买 nums[0] 与 nums[2]。
- 示例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
解题思路
- 最后卡在了全部都是
1
的样例上,并且这是最后一个样例,因此就想到了等差数列 - 等差数列前n项和
s(n) = n * a1 + n * (n - 1) / 2 * d
- 当数组中的所有元素都是相同的时候,就不需要再进行双层循环,只需要比较最开始的两个数值相加是否符合
<= target
,如果符合的话,那么数组中其他的任意两个相加也会满足,因此直接计算长度即可。 - 长度的计算:对于第一个元素往后找,符合的次数为
len - 1
,第二个元素符号的次数为len - 2
,依次类推往下.....,直到倒数第二个元素符合的次数为1
,倒数第一个元素符合的次数为0
- 总的来说:就是从
len - 1
一直加到0
,长度为len
,因此套用公式计算即可得到答案。
- 当数组中的所有元素都是相同的时候,就不需要再进行双层循环,只需要比较最开始的两个数值相加是否符合
总结
- 哈哈哈哈,这只是针对这一个样例的解决办法,如果样例中出现其他的符合条件的且数组中的元素不相同的时候,并且
target
很大,那么还是需要双层for
循环,一直遍历到超时。因此我去学习下别人的做法啦!共勉 - 类似题目:两数之和。要求两个数之和等于一个固定的值,但是现在这道题:需要选择找两个数,两数之和要小于固定的值。可以先将数组从大到小进行排序,然后用固定的值减去一个固定的数,再使用二分去查找符合要求的另一个数。
代码
var purchasePlans = function(nums, target) {
// 只购买两个零件,有多少种采购方案
// 取模
// 预处理排序
nums.sort((a, b) => {
return a - b;
});
// 特判一下
let ans = 0, len = nums.length, flag = false, mod = 10 ** 9 + 7;
for(let i = 1; i < len; i++) {
if(nums[i] != nums[i - 1]) flag = true;
}
if(!flag && (nums[0] + nums[1]) <= target) return (parseInt(len * (len - 1) / 2)) % mod;
// [2,3,5,5]
for(let i = 0; i < len; i++) {
for(let j = i + 1; j < len; j++) {
if(target >= nums[i] + nums[j]){
ans++;
}else{
break;
}
}
}
return ans % mod;
};