小扣在秋日市集选择了一家早餐摊位,一维整型数组 staple 中记录了每种主食的价格,一维整型数组 drinks 中记录了每种饮料的价格。小扣的计划选择一份主食和一款饮料,且花费不超过 x 元。请返回小扣共有多少种购买方案。
注意:答案需要以 1e9 + 7 (1000000007) 为底取模,如:计算初始结果为:1000000008,请返回 1
示例 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。
示例 2:
输入: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
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/2vYnGI
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
1.最基本的思路:暴力求解
通过依次排列组合,这样的解法会超时,测试例库中有非常变态的测试用例
[1,1,1,1,1,1,1,1,1,1,1,1,1…]
[1,1,1,1,1,1,1,1,1,1,1,1,1…]
2
//排列组合
int breakfastNumber(int* staple, int stapleSize, int* drinks, int drinksSize, int x){
int i;
int j;
int count=0;
for(i = 0; i < stapleSize; i++){
for(j = 0; j < drinksSize; j++){
if(staple[i]+drinks[j] <= x){
count = count % 1000000007;
count++;
}
}
}
return count;
}
2.优化
- 调用C库函数qsort(),先排序
- 进一步排列组合,减少组合次数,发现也超时
# define yichu 1000000007;
int compar(const void *p1,const void*p2){
const int * a1 = (const int *) p1;
const int * a2 = (const int *) p2;
if (*a1 < *a2)
return -1;
else if (*a1 == *a2)
return 0;
else
return 1;
}
int breakfastNumber(int* staple, int stapleSize, int* drinks, int drinksSize, int x){
int i;
int j;
int k = drinksSize-1;
int count=0;
qsort(staple,stapleSize,sizeof(int),compar);//默认升序
qsort(drinks,drinksSize,sizeof(int),compar);//默认升序
for(i =0; i < stapleSize ; i++){
for(j = k; j >= 0;j--){
if(staple[i]+drinks[j] <= x){
count = (count+(j+1)) % yichu;
k = j;//记录遍历的位置
break;
}
}
}
return count;
}
3.终极解法
#define mod 1000000007
int breakfastNumber(int* staple, int stapleSize, int* drinks, int drinksSize, int x){
int cnt[100001] = {0};
//类似哈希表,将数组元素的值写入新的数组,下标值即对应元素值
for (int i=0; i<drinksSize; ++i)
cnt[drinks[i]] += 1;
//计算数组中的每个下标前的元素个数。也就是某个计算饮料数组中小于等于此处下标值得元素个数
for (int i=1; i<100001; ++i)
cnt[i] += cnt[i-1];
long num = 0;
for (int i=0; i<stapleSize; ++i) {
int idx = x - staple[i];
//查看下标处的值(个数)
if (idx >= 0) {
idx = fmin(idx, 100000);//调用函数fmin(),当idx超过100000时,说明都符合要求,所以取数组下标为100000的值
num += cnt[idx];
if (num >= mod) num %= mod;
}
}
return num;
}