题目描述
小扣在秋日市集选择了一家早餐摊位,一维整型数组 staple
中记录了每种主食的价格,一维整型数组 drinks 中记录了每种饮料的价格。小扣的计划选择一份主食和一款饮料,且花费不超过 x
元。请返回小扣共有多少种购买方案。
注意:答案需要以 1e9 + 7 (1000000007)
为底取模,如:计算初始结果为:1000000008
,请返回 1
。
样例
输入:staple = [10,20,5], drinks = [5,5,2], x = 15
输出:6
解释:小扣有 6 种购买方案,所选主食与所选饮料在数组中对应的下标分别是:
第 1 种方案:staple[0] + drinks[0] = 10 + 5 = 15;
第 2 种方案:staple[0] + drinks[1] = 10 + 5 = 15;
第 3 种方案:staple[0] + drinks[2] = 10 + 2 = 12;
第 4 种方案:staple[2] + drinks[0] = 5 + 5 = 10;
第 5 种方案:staple[2] + drinks[1] = 5 + 5 = 10;
第 6 种方案:staple[2] + drinks[2] = 5 + 2 = 7。
输入:staple = [2,1,1], drinks = [8,9,5,1], x = 9
输出:8
解释:小扣有 8 种购买方案,所选主食与所选饮料在数组中对应的下标分别是:
第 1 种方案:staple[0] + drinks[2] = 2 + 5 = 7;
第 2 种方案:staple[0] + drinks[3] = 2 + 1 = 3;
第 3 种方案:staple[1] + drinks[0] = 1 + 8 = 9;
第 4 种方案:staple[1] + drinks[2] = 1 + 5 = 6;
第 5 种方案:staple[1] + drinks[3] = 1 + 1 = 2;
第 6 种方案:staple[2] + drinks[0] = 1 + 8 = 9;
第 7 种方案:staple[2] + drinks[2] = 1 + 5 = 6;
第 8 种方案:staple[2] + drinks[3] = 1 + 1 = 2。
限制
1 <= staple.length <= 10^5
1 <= drinks.length <= 10^5
1 <= staple[i],drinks[i] <= 10^5
1 <= x <= 2*10^5
算法
(双指针) $O(n \log n + m \log m)$
- 将
staple
数组从大到小排序,将drinks
数组从小到大排序。 - 维护 $i$ 和 $j$ 两个指针,对于
staple[i]
,我们找到尽可能小的 $j$,满足staple[i] + drinks[j] <= x
,这样答案就可以累计上 $j$ 个。 - 注意到,$j$ 是随着 $i$ 单调不降的。
时间复杂度
- 排序后,两个数组分别遍历一次,故总时间复杂度为 $O(n \log n + m \log m)$。
空间复杂度
- 仅需要常数的额外空间。
Go 代码
func breakfastNumber(staple []int, drinks []int, x int) int {
const mod = 1000000007
sort.Sort(sort.Reverse(sort.IntSlice(staple)))
sort.Ints(drinks)
var ans int
n, m := len(staple), len(drinks)
for i, j := 0, 0; i < n; i++ {
for j < m && staple[i] + drinks[j] <= x {
j++
}
ans = (ans + j) % mod;
}
return ans;
}