Maximum Fruits Harvested After at Most K Steps

hard sliding window prefix sum two pointers

Problem

Fruits sit on an infinite x-axis: fruits[i] = [position, amount], sorted by position. You start at startPos and may walk left and right for at most k total steps (one step = one unit). You collect every fruit at each position you visit. Return the maximum total amount of fruit you can harvest.

The key insight: an optimal route turns at most once, so the visited positions always form one contiguous interval. We slide a window over that interval, keeping it reachable within k steps. Reaching a window [L, R] costs (R − L) + min(|startPos − L|, |startPos − R|) — walk to the nearer end first, turn once, then sweep to the far end.

Inputfruits = [[2,8],[6,3],[8,6]], startPos = 5, k = 4
Output9
Move right to position 6 (3 fruits) then to position 8 (6 fruits): 3 steps, 3 + 6 = 9 fruits. Position 2 is too far left to also reach.

def maxTotalFruits(fruits, startPos, k):
    best = total = 0
    left = 0
    for right in range(len(fruits)):
        total += fruits[right][1]            # add new fruit to window sum
        # shrink while window [left..right] is unreachable in k steps
        while left <= right:
            lp, rp = fruits[left][0], fruits[right][0]
            cost = (rp - lp) + min(abs(startPos - lp),
                                   abs(startPos - rp))
            if cost <= k:
                break
            total -= fruits[left][1]         # drop the left fruit
            left += 1
        best = max(best, total)
    return best
function maxTotalFruits(fruits, startPos, k) {
  let best = 0, total = 0, left = 0;
  for (let right = 0; right < fruits.length; right++) {
    total += fruits[right][1];               // add new fruit to window sum
    // shrink while window [left..right] is unreachable in k steps
    while (left <= right) {
      const lp = fruits[left][0], rp = fruits[right][0];
      const cost = (rp - lp) +
        Math.min(Math.abs(startPos - lp), Math.abs(startPos - rp));
      if (cost <= k) break;
      total -= fruits[left][1];              // drop the left fruit
      left++;
    }
    best = Math.max(best, total);
  }
  return best;
}
int maxTotalFruits(int[][] fruits, int startPos, int k) {
    int best = 0, total = 0, left = 0;
    for (int right = 0; right < fruits.length; right++) {
        total += fruits[right][1];           // add new fruit to window sum
        // shrink while window [left..right] is unreachable in k steps
        while (left <= right) {
            int lp = fruits[left][0], rp = fruits[right][0];
            int cost = (rp - lp) + Math.min(Math.abs(startPos - lp),
                                            Math.abs(startPos - rp));
            if (cost <= k) break;
            total -= fruits[left][1];        // drop the left fruit
            left++;
        }
        best = Math.max(best, total);
    }
    return best;
}
int maxTotalFruits(vector<vector<int>>& fruits, int startPos, int k) {
    int best = 0, total = 0, left = 0;
    for (int right = 0; right < (int)fruits.size(); right++) {
        total += fruits[right][1];           // add new fruit to window sum
        // shrink while window [left..right] is unreachable in k steps
        while (left <= right) {
            int lp = fruits[left][0], rp = fruits[right][0];
            int cost = (rp - lp) + min(abs(startPos - lp),
                                       abs(startPos - rp));
            if (cost <= k) break;
            total -= fruits[left][1];        // drop the left fruit
            left++;
        }
        best = max(best, total);
    }
    return best;
}
Time: O(n) Space: O(1)