LeetCode 2106 摘水果(JavaScript)

解题思路:

区间和:

 这道题我用的是前缀和+区间的最大值,关于前缀和可以看一下这篇文章,LeetCode 任意子数组和绝对值的最大值(JavaScript)_猫弦920的博客-CSDN博客

区间的最大值,假如我们已经有了一个前缀和的数组 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;
        };

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值