[JavaScript / leetcode] LCP 28. 采购方案

96 阅读1分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 10 月更文挑战」的第4天,点击查看活动详情

每日刷题 2022.10.01

题目

  • 小力将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;
};