题目链接:2070. 每一个查询的最大美丽值 - 力扣(LeetCode)
看完本题,可以想到的思路是对于每一个查询queries[j],去遍历items数组,找到所有满足items[i][0]小于queries[j]的部分,再比较求出最大的items[i][1]即可。对于每一次的查询,最坏情况下每次需要遍历items数组一遍,时间复杂度太高,需要优化查询。
思路一:排序+双指针
- 将queries数组按照从小到大的顺序排序。
- 首先找所有 price<queries[0]的物品,求出最大值beaury。
- 接着找所有price<queries[1]的物品,由于已经知道price<queries[0]的最大beauty,所以只需求出queries[0]<=price<=querise[1]的最大beauty2,最后再取最大值即可。max(beauty,beauty2)。
- 以此类推,我们只需增量地计算所有满足queries[i-1]<=price<=queries[i]的物品的最大美丽值。
1,首先,将询问数组queries排序----升序,但由于anser需要按照原数组进行返回,所以可以创建queries的下标数组,对下标数组排序即可。
2,将物品的价值按照从小到大排序,然后双指针遍历满足queries[i-1]<price<queries[i]的物品。
class Solution {
public:
vector<int> maximumBeauty(vector<vector<int>>& items, vector<int>& queries) {
int n=queries.size();
//对物品的价值按照升序排序
sort(items.begin(),items.end());
//下标数组
vector<int> index(n);
for(int i=0;i<n;i++)
index[i]=i;
//排序下标数组,按照queries元素升序
sort(index.begin(),index.end(),[&](int i,int j)
{
return queries[i]<queries[j];
});
vector<int> ans(n);
//双指针遍历
int max_beauty=0,j=0;
for(int i:index)
{
int q=queries[i];
//queries[i-1]<=price<=queries[i]
while(j<items.size()&&items[j][0]<=q)
{
max_beauty=max(max_beauty,items[j][1]);
j++;
}
ans[i]=max_beauty;
}
return ans;
}
};
思路二:排序+二分查找
将items数组按照price价值升序排列,然后原地计算beauty的前缀最大值。即表示前i个物品中 ,将每个物品的beauty值修改为这些物品中最大的beauty值。
算好前缀最大值后,所有price<=queries[j]的物品的最大beauty,就保存在满足price<=queries[j]最右边的那个物品中。
我们可以二分查找满足price>queriees[j]的第一个位置,它的左边相邻物品就是要找的,如果左边没有物品,那么答案为0.
class Solution {
public:
vector<int> maximumBeauty(vector<vector<int>>& items, vector<int>& queries) {
sort(items.begin(),items.end());
//计算前缀最大值
for(int i=1;i<items.size();i++)
{
items[i][1]=max(items[i][1],items[i-1][1]);
}
//二分查找
for(int& q:queries)
{
int j=ranges::upper_bound(items,q,{},[](auto& item) {return item[0];})-items.begin();
q=j?items[j-1][1]:0;
}
return queries;
}
};
C++20中的ranges::upper_bound
upper_bound( R&& r, const T& value, Comp comp = {}, Proj proj = {} );
参数顺序依次是范围`r`、值`value`、比较器`comp`、投影`proj`。
没有自定义比较函数,因此使用默认的`ranges::less`。但默认情况下,比较器是`ranges::less{}`,而投影函数将元素转换为`item[0]`后再进行比较。