【LCP 28. 采购方案】二重循环(二分查找)/ 双指针

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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值