1. 问题分析与解题思路
这道题目描述的是从卡牌游戏中获取最大点数的问题。给定一个整数数组cardPoints表示卡牌的点数,每次只能从数组的最左侧或最右侧取一张卡牌,共取k次,求能获得的最大总点数。
1.1 问题重述与理解
想象你面前有一排卡牌,每张卡牌上都有一个点数。游戏规则是:
- 每次只能从最左边或最右边取一张牌
- 总共可以取k次
- 目标是使取到的牌的总点数最大
这实际上是一个典型的滑动窗口问题,我们需要找到k张牌的最佳组合方式。
1.2 关键观察点
通过分析题目,我们可以得出几个关键观察:
- 取牌的总次数固定为k次
- 每次取牌只能从两端取
- 最终取到的牌必然是左侧连续取i张,右侧连续取k-i张的组合(其中0≤i≤k)
这个观察是解题的核心,它让我们可以将问题转化为寻找最优的i值,使得左侧i张和右侧k-i张的总和最大。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 前缀和解法详解
2.1 前缀和概念
前缀和是一种预处理技术,它可以帮助我们快速计算数组中任意区间的和。对于数组arr,其前缀和数组prefix定义为:
- prefix[0] = 0
- prefix[i] = arr[0] + arr[1] + ... + arr[i-1]
这样,arr中从l到r的和可以快速计算为prefix[r+1] - prefix[l]。
2.2 前缀和的应用
在本问题中,我们使用前缀和来:
- 快速计算左侧取i张牌的总和(prefix[i])
- 快速计算右侧取k-i张牌的总和(prefix[n] - prefix[n-(k-i)])
这样,我们就能在O(1)时间内计算出任意i对应的总和,而不需要每次都重新计算。
2.3 算法步骤解析
让我们详细解析代码中的每个步骤:
- 初始化前缀和数组:
cpp复制vector<int> prefix{0};
for(int i = 0; i < n; i++) {
prefix.push_back(prefix.back() + cardPoints[i]);
}
这里我们构建了前缀和数组prefix,其中prefix[i]表示前i张牌的总和。
- 遍历所有可能的i值:
cpp复制for(int i = 0; i <= k; i++)
