网易首页 > 网易号 > 正文 申请入驻

2026-08-11:距离至少为 K 的交替子序列的最大和。用go语言,给定一个整数数组和一个整数 k,你需要从中挑选一个下标严格递增的子序列。

0
分享至

2026-08-11:距离至少为 K 的交替子序列的最大和。用go语言,给定一个整数数组和一个整数 k,你需要从中挑选一个下标严格递增的子序列。挑选时必须满足相邻两个下标之差至少为 k。同时,这些下标对应的数值必须构成一个严格交替的序列:即要么按照“小、大、小、大……”的模式波动,要么按照“大、小、大、小……”的模式波动,相邻元素之间的大小关系交替变化且不能相等。只包含一个元素的子序列也视为合法交替。该子序列的得分定义为其中所有元素之和。请你计算在所有满足条件的子序列中,能够获得的最大得分。

1 <= n == nums.length <= 100000。

1 <= nums[i] <= 100000。

1 <= k <= n。

输入: nums = [5,4,2], k = 2。

输出: 7。

解释:

一种最优选择是下标 [0, 2],对应的值为 [5, 2]。

距离条件成立,因为 2 - 0 = 2 >= k。

这些值严格交替,因为 5 > 2。

得分为 5 + 2 = 7。

题目来自力扣3915。

大体步骤如下: 1. 值域离散化

原数组中的数值范围可能较大(最大到 100000,但相对个数最多 100000),直接按值建立树状数组会浪费空间。因此先将所有数值排序、去重,得到一个紧凑的有序数组sorted。之后每个原始数值都可以用它在sorted中的下标(即排名)来表示,排名从0m-1m为不同值的个数)。这样就将值域压缩到了[0, m-1]的整数范围,便于树状数组处理。

2. 定义状态

对于每一个下标i,定义两种状态:

  • fInc[i]nums[i]结尾、且子序列最后两项呈现递增关系(即前一个数 <nums[i])的交替子序列的最大和。

  • fDec[i]nums[i]结尾、且子序列最后两项呈现递减关系(即前一个数 >nums[i])的交替子序列的最大和。

长度为 1 的子序列既可以视为“递增结尾”,也可以视为“递减结尾”,其和就是nums[i]本身。这两种状态覆盖了所有可能的交替模式(小大小大... 或 大小大小...)。

3. 初始化两个树状数组(Fenwick Tree)

树状数组用于维护值域区间内的最大 DP 值,支持单点取max更新和前缀最大值查询,每次操作均为O(log m)

  • inc树状数组:用于维护以递增结尾的状态fInc。为了能够方便地查询“值大于当前值”的所有状态,它在内部对索引进行了反转映射

  • dec树状数组:用于维护以递减结尾的状态fDec,采用原值域顺序,查询“值小于当前值”的状态。

两个树状数组大小均为m+1,使用 1‑based 索引。

4. 遍历数组,动态规划转移

按顺序遍历数组i = 0n-1,对每个元素x = nums[i]执行以下子步骤:

4.1 距离约束的“延迟加入”

题目要求选中子序列的相邻下标之差 ≥ k。为了满足这一条件,我们采用延迟激活的策略:
只有当i ≥ k时,才将下标i-k对应的状态加入到树状数组中,使其可以被当前及之后的下标使用。这保证了转移来源的原始下标与当前下标的距离至少为k

加入的具体操作为:

  • • 取出i-k位置已离散化的值j_prev(该值在之前遍历时已被替换为排名)。

  • • 更新inc:在位置m - j_prev上更新为max(原值, fInc[i-k])
    这一步利用了反转索引,把原本的“后缀查询”转化为树状数组擅长的“前缀查询”。

  • • 更新dec:在位置j_prev + 1上更新为max(原值, fDec[i-k])

4.2 当前元素的离散化

在当前元素x上使用二分查找,得到其在sorted中的排名j(0‑based)。为了后续步骤i+k能够直接使用该排名而无需再次二分,nums[i]就地修改为j(因为原值之后不再需要)。

4.3 计算当前状态

  • 计算fInc[i]:需要找一个前驱状态,它必须是递减结尾fDec),且其对应的值严格小于x(即排名< j)。
    dec树状数组中查询前缀[1, j](对应排名≤ j-1)的最大值,加上x即可得到fInc[i]。若不存在这样的前驱,查询返回0,则fInc[i] = x,对应单元素子序列。

  • 计算fDec[i]:需要找一个前驱状态,它是递增结尾fInc),且其值严格大于x(即排名> j)。
    通过反转索引,在inc树状数组中查询前缀[1, m-1-j](对应排名≥ j+1)的最大值,加上x得到fDec[i]

4.4 更新全局答案

用刚刚算出的fInc[i]fDec[i]去更新全局最大得分ans

5. 输出结果

遍历完整个数组后,ans即为所有满足条件的子序列的最大得分。

复杂度分析

  • 时间复杂度
    离散化排序O(n log n);主循环执行n次,每次包含一次二分查找O(log m)和两次树状数组操作(更新/查询)均为O(log m)。由于m ≤ n,总时间复杂度为O(n log n)

  • 额外空间复杂度
    离散化数组sorted占用O(m);DP 数组fIncfDec各占用O(n);两个树状数组各占用O(m)。整体额外空间为O(n)

Go完整代码如下:

package main

import (
"fmt"
"slices"
"sort"
)

type fenwick []int64

func (f fenwick) update(i int, val int64) {
for ; i < len(f); i += i & -i {
f[i] = max(f[i], val)
}
}

// [1, i] 中的最大值
func (f fenwick) preMax(i int) (res int64) {
for ; i > 0; i &= i - 1 {
res = max(res, f[i])
}
return
}

func maxAlternatingSum(nums []int, k int) (ans int64) {
// 离散化 nums
sorted := slices.Clone(nums)
slices.Sort(sorted)
sorted = slices.Compact(sorted)

n := len(nums)
fInc := make([]int64, n) // fInc[i] 表示以 nums[i] 结尾且最后两项递增的交替子序列的最大和
fDec := make([]int64, n) // fDec[i] 表示以 nums[i] 结尾且最后两项递减的交替子序列的最大和

// 值域树状数组
m := len(sorted)
inc := make(fenwick, m+1) // 维护 fInc[i] 的最大值
dec := make(fenwick, m+1) // 维护 fDec[i] 的最大值

for i, x := range nums {
if i >= k {
// 在这个时候才把 fInc[i-k] 和 fDec[i-k] 添加到值域树状数组中,从而保证转移来源的下标 <= i-k
j := nums[i-k]
inc.update(m-j, fInc[i-k]) // m-j 可以把后缀变成前缀
dec.update(j+1, fDec[i-k])
}

j := sort.SearchInts(sorted, x)
nums[i] = j // 注意这里修改了 nums[i],这样上面的 nums[i-k] 无需二分

fInc[i] = dec.preMax(j) + int64(x) // 计算满足 nums[i'] < x 的 fDec[i'] 的最大值
fDec[i] = inc.preMax(m-1-j) + int64(x) // 计算满足 nums[i'] > x 的 fInc[i'] 的最大值
ans = max(ans, fInc[i], fDec[i]) // 枚举子序列以 nums[i] 结尾
}

return
}

func main() {
nums := []int{5, 4, 2}
k := 2
result := maxAlternatingSum(nums, k)
fmt.Println(result)
}

Python完整代码如下:

# -*-coding:utf-8-*-

from typing import List
import bisect

class Fenwick:
"""树状数组,维护前缀最大值(1-indexed)"""
def __init__(self, n: int):
self.tree = [0] * (n + 1)
self.n = n

def update(self, i: int, val: int) -> None:
"""将位置 i 的值更新为 max(tree[i], val)"""
while i <= self.n:
if val > self.tree[i]:
self.tree[i] = val
i += i & -i

def pre_max(self, i: int) -> int:
"""查询 [1, i] 中的最大值"""
res = 0
while i > 0:
if self.tree[i] > res:
res = self.tree[i]
i &= i - 1
return res

def max_alternating_sum(nums: List[int], k: int) -> int:
# 离散化:获取去重排序后的数值
sorted_nums = sorted(set(nums))
m = len(sorted_nums)

# 两个树状数组:
# inc 维护 f_inc(以递增结尾的交替子序列最大和)
# dec 维护 f_dec(以递减结尾的交替子序列最大和)
inc = Fenwick(m)
dec = Fenwick(m)

n = len(nums)
f_inc = [0] * n
f_dec = [0] * n
ans = 0

for i, x in enumerate(nums):
# 只有当下标距离至少为 k 时,才将 i-k 的状态加入树状数组
if i >= k:
j_prev = nums[i - k] # 之前已经替换为离散化索引
inc.update(m - j_prev, f_inc[i - k])
dec.update(j_prev + 1, f_dec[i - k])

# 当前元素离散化
j = bisect.bisect_left(sorted_nums, x)
nums[i] = j # 替换为索引,供后续使用

# 计算以当前元素结尾的两种状态
# f_inc: 之前递减结尾,且前一个数 < 当前数
f_inc_i = dec.pre_max(j) + x
# f_dec: 之前递增结尾,且前一个数 > 当前数
f_dec_i = inc.pre_max(m - 1 - j) + x

f_inc[i] = f_inc_i
f_dec[i] = f_dec_i

if f_inc_i > ans:
ans = f_inc_i
if f_dec_i > ans:
ans = f_dec_i

return ans

if __name__ == "__main__":
nums = [5, 4, 2]
k = 2
result = max_alternating_sum(nums, k)
print(result)

C++完整代码如下:

  



using namespace std;

class Fenwick {
vector tree;
public:
Fenwick(int n) : tree(n + 1, 0) {}

// 更新位置 i(1-indexed)的值为 max(tree[i], val)
void update(int i, long long val) {
while (i < (int)tree.size()) {
tree[i] = max(tree[i], val);
i += i & -i;
}
}

// 查询前缀 [1, i] 的最大值
long long preMax(int i) const {
long long res = 0;
while (i > 0) {
res = max(res, tree[i]);
i &= i - 1;
}
return res;
}
};

long long maxAlternatingSum(vector& nums, int k) {
// 离散化
vector sorted = nums;
sort(sorted.begin(), sorted.end());
sorted.erase(unique(sorted.begin(), sorted.end()), sorted.end());
int m = sorted.size();

int n = nums.size();
vector fInc(n, 0), fDec(n, 0); // 注意初始化为 0(空子序列和为 0)

Fenwick inc(m), dec(m); // 内部数组大小为 m+1,支持 1..m 索引
long long ans = 0;

for (int i = 0; i < n; ++i) {
int x = nums[i];
// 距离至少 k 时,将 i-k 的状态加入树状数组
if (i >= k) {
int j_prev = nums[i - k]; // 之前已替换为离散化索引
inc.update(m - j_prev, fInc[i - k]);
dec.update(j_prev + 1, fDec[i - k]);
}

// 当前元素的离散化索引
int j = lower_bound(sorted.begin(), sorted.end(), x) - sorted.begin();
nums[i] = j; // 替换原值,后续直接使用索引

// 状态转移
fInc[i] = dec.preMax(j) + x; // 之前递减结尾,且前一个数 < 当前数
fDec[i] = inc.preMax(m - 1 - j) + x; // 之前递增结尾,且前一个数 > 当前数

ans = max({ans, fInc[i], fDec[i]});
}

return ans;
}

int main() {
vector nums = {5, 4, 2};
int k = 2;
long long result = maxAlternatingSum(nums, k);
cout << result << endl;
return 0;
}

我们相信人工智能为普通人提供了一种“增强工具”,并致力于分享全方位的AI知识。在这里,您可以找到最新的AI科普文章、工具评测、提升效率的秘籍以及行业洞察。 欢迎关注“福大大架构师每日一题”,发消息可获得面试资料,让AI助力您的未来发展。

特别声明:以上内容(如有图片或视频亦包括在内)为自媒体平台“网易号”用户上传并发布,本平台仅提供信息存储服务。

Notice: The content above (including the pictures and videos if any) is uploaded and posted by a user of NetEase Hao, which is a social media platform and only provides information storage services.

相关推荐
热点推荐
俄罗斯四年没看透,伊朗五个月悟了!不打痛美盟友,仗永远赢不了

俄罗斯四年没看透,伊朗五个月悟了!不打痛美盟友,仗永远赢不了

原来仙女不讲理
2026-08-14 15:15:04
邹市明霸气护妻,辟谣并宣布追究造谣者的法律责任

邹市明霸气护妻,辟谣并宣布追究造谣者的法律责任

映射生活的身影
2026-08-14 17:34:40
80年代中美蜜月期,中国拿了多少美械装备?该告诉大家实情了!

80年代中美蜜月期,中国拿了多少美械装备?该告诉大家实情了!

抽象派大师
2026-06-30 01:45:32
终极反杀!俄乌战局,突传大消息!

终极反杀!俄乌战局,突传大消息!

大嘴说天下
2026-08-12 21:35:06
震惊!30多岁女生开心发帖称,在马来西亚仙本那旅游,被22岁潜水教练表白,没想到众口一词说小姐姐被骗财骗色了

震惊!30多岁女生开心发帖称,在马来西亚仙本那旅游,被22岁潜水教练表白,没想到众口一词说小姐姐被骗财骗色了

火山詩话
2026-08-12 08:31:04
韩媒曾警告:一旦东亚开战,韩导弹将轰炸北京,同时摧毁中国海军

韩媒曾警告:一旦东亚开战,韩导弹将轰炸北京,同时摧毁中国海军

坦荡的雪莉
2026-08-14 13:07:07
能冻老冰棍!特斯拉Model Y车载冰箱上线:2499元 比北美便宜四成

能冻老冰棍!特斯拉Model Y车载冰箱上线:2499元 比北美便宜四成

快科技
2026-08-13 18:25:09
菲军方警告中国!只要中方敢出手,菲律宾就直接开战,后果自负

菲军方警告中国!只要中方敢出手,菲律宾就直接开战,后果自负

掌秋看世界
2026-06-24 17:45:05
美媒:张振熙或接任白宫新闻秘书

美媒:张振熙或接任白宫新闻秘书

中国网
2026-08-14 18:07:02
连锁火锅店内有顾客抱孩子在小料台旁垃圾桶小便,门店回应→

连锁火锅店内有顾客抱孩子在小料台旁垃圾桶小便,门店回应→

北青网-北京青年报
2026-08-14 09:20:04
高速限速140km/h试点:省7分钟,但你的车和钱包扛得住吗?

高速限速140km/h试点:省7分钟,但你的车和钱包扛得住吗?

匹夫来搞笑
2026-08-13 05:45:17
梅德韦杰夫:南千岛群岛过去、现在、将来都是俄领土

梅德韦杰夫:南千岛群岛过去、现在、将来都是俄领土

新华社
2026-08-13 21:50:03
普京只剩两条路?俄乌冲突的真正死局来了

普京只剩两条路?俄乌冲突的真正死局来了

民间胡扯老哥
2026-08-14 12:59:36
七月初三送别22岁程梦圆,灵棚隔路搭建,藏着乡土的心疼

七月初三送别22岁程梦圆,灵棚隔路搭建,藏着乡土的心疼

社会日日鲜
2026-08-13 17:25:58
“没有任何不舒服”,6岁孩子做头颅CT,意外发现6颗异物,爸妈脊背发凉:这是2021年买的

“没有任何不舒服”,6岁孩子做头颅CT,意外发现6颗异物,爸妈脊背发凉:这是2021年买的

中国网
2026-08-12 15:34:28
广东283个镇街遭遇暴雨、大暴雨

广东283个镇街遭遇暴雨、大暴雨

中国能源网
2026-08-14 15:24:16
儿子高考712分,被北京清北拒收,父托关系查卷,卷上3字让他崩溃

儿子高考712分,被北京清北拒收,父托关系查卷,卷上3字让他崩溃

马蹄烫嘴说美食
2026-08-14 09:08:41
2026年,企退人员的养老金重算补发,哪些人每月能涨200元呢?

2026年,企退人员的养老金重算补发,哪些人每月能涨200元呢?

碎月说
2026-08-14 11:37:08
特朗普老婆跑了?美国第一夫人人间蒸发,大难临头各自飞了?

特朗普老婆跑了?美国第一夫人人间蒸发,大难临头各自飞了?

探源历史
2026-08-14 00:25:18
“新型出轨方式”正悄然兴起,不私会不开房,却正在毁掉千万家庭

“新型出轨方式”正悄然兴起,不私会不开房,却正在毁掉千万家庭

流史岁月
2026-08-10 10:46:45
2026-08-14 18:55:00
moonfdd incentive-icons
moonfdd
福大大架构师每日一题
1392文章数 79关注度
往期回顾 全部

科技要闻

苹果为中国训练自有大模型,阿里提供支持

头条要闻

老人被撞身亡肇事车仅有交强险 司机当庭称没能力赔偿

头条要闻

老人被撞身亡肇事车仅有交强险 司机当庭称没能力赔偿

体育要闻

离开雷霆后,威少再也没成为威少

娱乐要闻

郭麒麟瘦到全网认不出,为新剧塑形

财经要闻

便利蜂加盟遭立案:“0元加盟”生意被查

汽车要闻

长安启源Q06-吉克隽逸

态度原创

教育
房产
时尚
亲子
本地

教育要闻

2026高考最让人难以置信的一幕:浙江668高分考生竟滑档?太吓人

房产要闻

金茂、招商,海南多个岗位招人!

这4种版型的牛仔裤,真的很好穿!

亲子要闻

宝蓝准备了很多音乐玩具,在家里和家人办起了音乐会,好听又好玩

本地新闻

黄景藏用半刀泥刻瓷都魂

无障碍浏览 进入关怀版