- 基本思想:找出最优解所满足的形式(即必要条件),然后在这样的条件下通过搜索的方式找出最优解
- 首先,最优路径一定是先向左走到头(这里的头指的是最优解的边界),然后再向右走到头,最多转向一次,或者先向右走到头,然后再向左走到头,最多转向一次
- 设原点为startPosstartPosstartPos,以原点向左走的最大步数为xxx,以原点向右走的最大步数为yyy。
当采用前一种做法时原问题为:
求[startpos−x,startpos+y][startpos - x,startpos +y][startpos−x,startpos+y]区间内水果的最大数目,在满足约束条件2x+y≤k2x + y \leq k2x+y≤k,x≤yx \leq yx≤y的条件下。
- 在给定xxx的条件下,要使得区间尽量大,显然有y=k−2xy = k - 2xy=k−2x
- 并且x≤yx \leq yx≤y,否则可以使用后一种做法(先向右走到尽头,再向左走到尽头)而使得步数k还没有用尽
原问题转换为:求得一个大于等于0得正整数xxx使得区间[startpos−x,startpos+k−2x][startpos - x,startpos + k - 2x][startpos−x,startpos+k−2x]中水果数目达到最大值。
- 并且需要满足k−2x≥0,x≥0,3x≤kk - 2x \geq 0,x \geq 0,3x \leq kk−2x≥0,x≥0,3x≤k,由于第一个不等式必须成立,且注意到整数,因此约束条件为0≤x≤⌊k/3⌋0\leq x \leq \lfloor k/3 \rfloor0≤x≤⌊k/3⌋
- 在这个区间上执行搜索xxx,找到最优的xxx对应的值即可得到结果。
- 可在最大数据范围内维护数轴的前缀和即可实现,pre[i]表示截止i位置的pre[i]表示截止i位置的pre[i]表示截止i位置的所有水果个数。欲求任意区间的数值可直接用两个前缀和详见即可
当采用后一种做法时原问题为:
求[startpos−x,startpos+y][startpos - x,startpos +y][startpos−x,startpos+y]区间内水果的最大数目,在满足约束条件x+2y≤kx + 2y \leq kx+2y≤k,x>=yx >=yx>=y的条件下。
- 即: 求[startpos−k+2y,startpos+y][startpos - k + 2y,startpos +y][startpos−k+2y,startpos+y]区间内水果的最大数目,在满足约束条件 0≤y<=⌊k/3⌋0\leq y<= \lfloor k/3\rfloor0≤y<=⌊k/3⌋的条件下
class Solution {
public int maxTotalFruits(int[][] fruits, int startPos, int k) {
int[] pre = new int[200001]; //保存前缀和
//统计前缀和
int i ;
int next ;
if(fruits[0][0] == 0)
{
pre[0] = fruits[0][1];
next = 1;
}
else
{
pre[0] = next = 0;
}
for(i = 1;i<pre.length && next < fruits.length;i++)
{
if(i == fruits[next][0])
{
pre[i] = pre[i - 1] + fruits[next][1];
next++;
}
else pre[i] = pre[i - 1];
}
for(;i<pre.length;i++)
pre[i] = pre[i - 1];
int ans = 0;
for(int x = 0;x<=k/3;x++)
{
int lower = startPos - x <=0?0:pre[startPos - x - 1];
int upper = startPos + k - 2*x >= 200000?pre[200000] : pre[startPos + k - 2*x];
ans = Math.max(ans,upper - lower);
}
for(int y = 0;y<=k/3;y++)
{
int lower = startPos - k + 2*y<=0?0:pre[startPos - k + 2*y - 1];
int upper = startPos + y>=200000?pre[200000]:pre[startPos + y];
ans = Math.max(ans,upper - lower);
}
return ans;
}
}