摘水果
x坐标轴上分配了水果的位置(升序)和个数
给你一个开始位置和步数,可以选择往左或往右,返回可以摘到的最大水果数
1. 二分查找+前缀和+滑动窗口
枚举先左后右和先右后左两种情况下的左右边界,利用二分和前缀和快速求值
class Solution {
public:
int maxTotalFruits(vector<vector<int>>& fruits, int startPos, int k) {
int n = fruits.size();
vector<int> presum(n + 1);//前缀和
vector<int> indices(n);//单独用来二分
for (int i = 0; i < n; i++) {
presum[i + 1] = presum[i] + fruits[i][1];
indices[i] = fruits[i][0];
}
int res = 0;
for (int x = 0; x <= k / 2; x++) {
/* 向左走 x 步,再向右走 k - x 步 */
int y = k - 2 * x;//往右的距离
int left = startPos - x;//左边界
int right = startPos + y;//右边界
int start = lower_bound(indices.begin(), indices.end(), left) - indices.begin();//左闭
int end = upper_bound(indices.begin(), indices.end(), right) - indices.begin();//右开
//这里end相当于end的前一个位置,即所能到达右侧最远位置,其前缀和
res = max(res, presum[end] - presum[start]);
/* 向右走 x 步,再向左走 k - x 步 */
y = k - 2 * x;
left = startPos - y;
right = startPos + x;
start = lower_bound(indices.begin(), indices.end(), left) - indices.begin();
end = upper_bound(indices.begin(), indices.end(), right) - indices.begin();
res = max(res, presum[end] - presum[start]);
}
return res;
}
};