解题思路:
区间和:
这道题我用的是前缀和+区间的最大值,关于前缀和可以看一下这篇文章,LeetCode 任意子数组和绝对值的最大值(JavaScript)_猫弦920的博客-优快云博客
区间的最大值,假如我们已经有了一个前缀和的数组 preSum,那么 [i,j]这个区间的和,就应该是preSum[j+1]-preSum[i],大家可以先想一想,再接着往下看:
为什么是这样呢,因为preSum[i]=preSum[i-1]+nums[i],那么preSum[i]是nums[0,i-1]的和,这里的i要大于等于1,preSum[j+1] 就是 nums[0,j] 的和。
人物走向问题:
现在我们了解了一个区间的和,那么我们再来看这道题,我们发现这个人走有四种情况
- 一直往左走
- 一直往右走
- 先左后右
- 现右后左
如果走了走了左再往右走再往左走,这样同一条的路走了很多次,就很难得到最大值。
关于往左走的 left 的值和往右走的 right 的值:
通过这张图我们可以发现,如果只是单纯的:
let right = startPos + i;
let left = right - k + i;
就会发现一个很严肃的问题,比如我们看上图的 right = 3,left = 1,那么这里应该是第三步,所以i=3,我们看上面的那个式子,发现,right = 5 + 3 = 8,我们发现人确实走到了索引为8的地方,那么 left 也等于7,咋的一看,好像没啥啊,但是如果你要求区间和的话就有很大的问题了,如果按照我们之前求的那么我们求的是[7,8]区间的和。
这题目有很多坑,先把大体的思路把握好,再对细节部分慢慢处理,下面有些用例就是一些坑,可以慢慢测试他们,慢慢更改他们。
测试用例:
-
var fruits = [[0, 10000]], startPos = 0, k = 0;
-
var fruits = [[200000, 10000]], startPos = 0, k = 0;
-
var fruits = [[0, 10000]], startPos = 0, k = 200000;
-
var fruits = [[0, 10000]], startPos = 200000, k = 0;
-
var fruits = [[0, 2]], startPos = 0, k = 2;
-
var fruits = [[7320, 774], [7321, 974]], startPos = 72940, k = 65618;
下面是我的写的代码,可能好多地方写的不是很好,有些地方完全是根据测试用例慢慢更改的,但是大体思路就是我上面讲的。
通过代码:
var maxTotalFruits = function (fruits, startPos, k) {
let preSum = new Array(fruits[fruits.length - 1][0] + 1);
let sum = 0;
preSum.fill(0);
for (let i = 0; i < fruits.length; i++) {
sum += fruits[i][1];
if (i != fruits.length - 1) {
preSum.fill(sum, fruits[i][0], fruits[i + 1][0]);
continue;
}
preSum[fruits[i][0]] = sum;
preSum.push(sum);
}
// 如果待在原地
if (k == 0 && startPos != 0) {
return preSum[startPos] == undefined ? 0 : preSum[startPos] - preSum[startPos - 1];
} else if (k == 0) {
return preSum[startPos] == undefined ? 0 : preSum[startPos];
}
let max = 0;
// 先左后右
for (let i = 1; i <= k; i++) {
let left = Math.max(0, startPos - i);
let right = Math.min(preSum.length - 1, Math.max(left + k - i, startPos));
sum = preSum[right] - (left == 0 ? 0 : preSum[left - 1]);
if (isNaN(sum)) {
preSum.pop();
if (preSum[startPos - k] == undefined) {
return 0;
} else {
if (preSum[Math.max(startPos, k)] == undefined) {
if ((startPos - k) != 0) {
return preSum[preSum.length - 1] - preSum[startPos - k - 1];
} else {
return preSum[preSum.length - 1];
}
} else {
return preSum[Math.max(startPos, k)] - preSum[Math.max(startPos, k) - Math.min(startPos, k) > 0 ? Math.max(startPos, k) - Math.min(startPos, k) - 1 : 0];
}
}
}
if (max < sum) {
max = sum;
}
}
// 先右后左
for (let i = 1; i <= k; i++) {
let right = Math.min(preSum.length - 1, startPos + i);
let left = Math.max(0, Math.min(right - k + i, startPos));
sum = preSum[right] - (left == 0 ? 0 : preSum[left - 1]);
if (max < sum) {
max = sum;
}
}
return max;
};