题目
在神秘的地牢中,n
个魔法师站成一排。每个魔法师都拥有一个属性,这个属性可以给你提供能量。有些魔法师可能会给你负能量,即从你身上吸取能量。
你被施加了一种诅咒,当你从魔法师 i
处吸收能量后,你将被立即传送到魔法师 (i + k)
处。这一过程将重复进行,直到你到达一个不存在 (i + k)
的魔法师为止。
换句话说,你将选择一个起点,然后以 k
为间隔跳跃,直到到达魔法师序列的末端,在过程中吸收所有的能量。
给定一个数组 energy
和一个整数k
,返回你能获得的 最大 能量。
示例 1:
输入: energy = [5,2,-10,-5,1], k = 3
输出: 3
解释:可以从魔法师 1 开始,吸收能量 2 + 1 = 3。
示例 2:
输入: energy = [-2,-3,-1], k = 2
输出: -1
解释:可以从魔法师 2 开始,吸收能量 -1。
链接
100274. 从魔法师身上吸取的最大能量 - 力扣(LeetCode)第 397 场周赛 - 力扣(LeetCode)
解题思路
这一道题相当于是从数组中的某一个元素开始,依次间隔k的元素,到结束的和的最大值,首先来看暴力解法,两个for循环,外层for循环遍历所有元素,内层for循环累加间隔k的和,但是这样会超时,接着来看看优化,比如说这个用例energy = [5,2,-10,-5,1], k = 2,从5开始,5+(-10)+(1),2+(-5),(-10)+1,-5,1,这是暴力解法的情况,我们会发现从(-10)开始算的话其实就已经重复了,因为在第一次算的时候就已经算过了,知道这里就可以进行优化了,5+(-10)是大于(-10)的,也就是说如果我们再次算到(-10)的时候其实就已经不用算了,因为要求出来的是最大值,前面的累加已经使结果大于自己了,再从自己算,不就变小了吗。如果他是小于的,那么我们就没必要要前面的值。
还是以这个为例,energy = [5,2,-10,-5,1], k = 2.我们新取一个数组arr[7],让第一个元素设置为0,即arr[0]=0,如果下标超出数组长度了就不需要累加,当下标小于等于k时,我们让前k个元素直接进行一次累加,接着arr[1]=5+(-10)=-5,arr[2]=2+(-5)=-3,,当下标大于k时,就开始重复了,此时判断arr[3]是否需要在arr[3-k]的基础上进行累加,如果arr[3-k]小于arr[3]的话,就不需要,否则就需要,那么arr[3]=arr[1]+1=-4,后面同理判断,arr[4] = arr[2] = -3(此时下标已经越界了,就不需要找下一个间隔为k的元素了),arr[5] = 1。
再来看个长一点的用例,energy =[5,-10,4,3,5,-9,9,-7,4],k =2,arr[10]。
下标小于等于k
arr[1] = energy[0] + energy[0+k] = 9,
arr[2] = energy[1] + energy[1+k] = -7,
下标大于k
arr[3] = arr[1] + energy[2+k] = 14,
arr[4] = energy[3] + energy[3+k] = -6;
arr[5] = arr[3] + energy[4+k] = 23,
arr[6] = arr[4] + energy[5+k] = -13,
arr[7] = arr[5] + energy[6+k] = 27,
arr[8] = energy[7] = -7,
arr[9] = arr[7] = 27.
此时最后k个元素比较就是我们要的值了。
注意一个小细节就是数组不要越界。
下面是ac代码
class Solution {
public:
int maximumEnergy(vector<int>& energy, int k) {
int ret = INT_MIN,n = energy.size();
vector<int> v(n+1,0);
for(int i = 1;i<n+1;i++)
{
if(i<=k)
{
if(i-1+k<n)
v[i] = energy[i-1]+energy[i-1+k];
else
v[i] = energy[i-1];
}
else
{
int tmp = v[i-k]>energy[i-1]?v[i-k]:energy[i-1];
if(i-1+k<n)
v[i] = tmp + energy[i-1+k];
else
v[i] = tmp;
}
if(i>n-k) ret = max(ret,v[i]);
}
return ret;
}
};