学习笔记参考:https://leetcode.cn/leetbook/read/qian-zhui-he/nk1f5i/
一维前缀和
前缀和是算法题中一个重要的技巧,经常作为一种优化方式出现在其他算法的一些子环节中。本课程就来带着同学们整理与巩固前缀和相关知识点,在学习完本课程之后,希望同学们对前缀和的思想有一个更加深入的理解。
本小节所需前置知识:语言基础
本小节所讲述的知识:一维前缀和
TBD
3147. 从魔法师身上吸取的最大能量
在神秘的地牢中,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。
提示:
1 <= energy.length <= 10^5
-1000 <= energy[i] <= 1000
1 <= k <= energy.length - 1
朴素解法1(超时)
int maximumEnergy(int *energy, int energySize, int k)
{
int *res = (int*)malloc(sizeof(int) * energySize);
memset(res, 0, sizeof(int) * energySize);
int j = 0;
for (int i = 0; i < energySize; i++) {
// res[i] = energy[i];
int cnt = (energySize + k - 1) / k;
j = 0;
while ((i + j * k < energySize) && (cnt > 0)) {
res[i] = res[i] + energy[i + j * k];
j++;
cnt--;
}
}
for (j = 0; j < (energySize); j++) {
printf("%d ", res[j]);
}
int result = -1001;
for (int i = 0; i < energySize; i++) {
result = fmax(result, res[i]);
}
return result;
}
int main()
{
int energy[3] = {-2, -3, -1};
int energySize = 3;
int k = 2;
int ret = maximumEnergy(energy, energySize, k);
return 0;
}

k = 1
从特殊到一般,先想一想,k=1 怎么做?
此时只能一步一步地向右走。无论起点在哪,终点都是 n−1。
如果选择 i 为起点,我们计算的是子数组 [i,n−1] 的元素和,即后缀和。
后缀和怎么算?我们可以倒着遍历 energy,同时累加元素和,即为后缀和。
答案等于所有后缀和的最大值。
k = 2
再想一想,k=2 怎么做?
此时我们有两个终点:n−2 和 n−1。
对于终点 n−1:
如果选择 n−3 为起点,那么我们累加的是下标为 n−3,n−1 的元素和。
如果选择 n−5 为起点,那么我们累加的是下标为 n−5,n−3,n−1 的元素和。
如果选择 n−7 为起点,那么我们累加的是下标为 n−7,n−5,n−3,n−1 的元素和。
一般地,从 n−1 开始倒着遍历,步长为 −k=−2,累加元素和,计算元素和的最大值。
对于终点 n−2:
如果选择 n−4 为起点,那么我们累加的是下标为 n−4,n−2 的元素和。
如果选择 n−6 为起点,那么我们累加的是下标为 n−6,n−4,n−2 的元素和。
如果选择 n−8 为起点,那么我们累加的是下标为 n−8,n−6,n−4,n−2 的元素和。
一般地,从 n−2 开始倒着遍历,步长为 −k=−2,累加元素和,计算元素和的最大值。
是否可以从 n−3 开始倒着遍历?
不行,因为 n−3 还可以向右跳到 n−1,所以 n−3 不是终点,不能作为倒着遍历的起点。
一般情况
枚举终点 n−k,n−k+1,…,n−1,倒着遍历,步长为 −k。
遍历的同时累加元素和 sufSum,计算 sufSum 的最大值,即为答案。
#define MAX(a, b) ((b) > (a) ? (b) : (a))
int maximumEnergy(int* energy, int energySize, int k){
int ans = INT_MIN;
for (int i = energySize - k; i < energySize; i++) { // 枚举终点 i,k个
int suf_sum = 0;
for (int j = i; j >= 0; j -= k) {
suf_sum += energy[j]; // 计算后缀和
ans = MAX(ans, suf_sum);
}
}
return ans;
}
本文将介绍一维前缀和这一算法技巧,其常用于优化其他算法,并帮助读者巩固相关知识点,以期提升对前缀和思想的理解。前置知识包括语言基础,目标是深入掌握一维前缀和的应用。

被折叠的 条评论
为什么被折叠?



