题目
给你一个长度为 n 的整数数组 nums ,和一个长度为 m 的整数数组 queries 。
返回一个长度为 m 的数组 answer ,其中 answer[i] 是 nums 中 元素之和小于等于 queries[i] 的 子序列 的 最大 长度 。
子序列 是由一个数组删除某些元素(也可以不删除)但不改变剩余元素顺序得到的一个数组。
示例 1:
输入:nums = [4,5,2,1], queries = [3,10,21]
输出:[2,3,4]
解释:queries 对应的 answer 如下:
- 子序列 [2,1] 的和小于或等于 3 。可以证明满足题目要求的子序列的最大长度是 2 ,所以 answer[0] = 2 。
- 子序列 [4,5,1] 的和小于或等于 10 。可以证明满足题目要求的子序列的最大长度是 3 ,所以 answer[1] = 3 。
- 子序列 [4,5,2,1] 的和小于或等于 21 。可以证明满足题目要求的子序列的最大长度是 4 ,所以 answer[2] = 4 。
示例 2:
输入:nums = [2,3,4,5], queries = [1]
输出:[0]
解释:空子序列是唯一一个满足元素和小于或等于 1 的子序列,所以 answer[0] = 0 。
答案
vector<int> answerQueries(vector<int>& nums, vector<int>& queries) {
vector<int> res;
int n = nums.size();
int m = queries.size();
//nums从小到大排序
sort(nums.begin(),nums.end());
vector<int> f(n+1);
//存储前缀和
for(int i=0;i<n;i++){
f[i+1] = f[i] + nums[i];
}
//找第一个大于目标序列的值
for(int i=0;i<m;i++){
int r = upper_bound(f.begin(),f.end(),queries[i])-f.begin()-1;
res.push_back(r);
}
return res;
}
知识点1
//前缀和
void addTotal(){
vector<int> nums = {1,2,3,4,5,6};
vector<int> res(6+1);
for(int i=0;i<nums.size();i++){
//res第一个为0,res[1]为nums前1个的和,res[2]为nums前2个的和
res[i+1] = res[i] + nums[i];
}
for(int i=0;i<res.size();i++){
cout<<res[i]<<" ";
}
}
知识点2
upper_bound( begin,end,num):从数组的begin位置到end-1位置二分查找第一个大于num的数字,找到返回该数字的地址,不存在则返回end。通过返回的地址减去起始地址begin,得到找到数字在数组中的下标。
ower_bound( begin,end,num):从数组的begin位置到end-1位置二分查找第一个大于或等于num的数字,找到返回该数字的地址,不存在则返回end。通过返回的地址减去起始地址begin,得到找到数字在数组中的下标。
lower_bound( )和upper_bound( )都是利用二分查找的方法在一个排好序的数组中进行查找的。
# 计算出前缀和数组中第一个大于queries[i]的数据索引位置
int r = upper_bound(f.begin(),f.end(),queries[i])-f.begin()-1;