可获得的最大点数-LeetCode
1423. 可获得的最大点数
🎯 问题描述(来源于LeetCode)
描述:
几张卡牌排成一行,每张卡牌都有一个对应的点数。点数由整数数组 cardPoints 给出。
每次行动,你可以从行的开头或者末尾拿一张卡牌,最终你必须正好拿 k 张卡牌。
你的点数就是你拿到手中的所有卡牌的点数之和。
返回可以获得的最大点数。
说明:
-
这是一个典型的**“逆向思维 + 滑动窗口”**问题。
-
从两端取
k个元素使得和最大,等价于在数组中间保留n-k个连续元素使得和最小。 -
最大得分 = 数组总和 - 中间连续子数组的最小和。
-
示例:
-
示例 1:
1 | 输入:cardPoints = [1,2,3,4,5,6,1], k = 3 |
- 示例 2:
1 | 输入:cardPoints = [9,7,7,9,7,7,9], k = 7 |
💻 解题思路
思路1:逆向思维 + 定长滑动窗口
思路1:代码实现
1 | class Solution: |
思路1:📊 性能分析
- 时间复杂度:
- 其中 是数组
cardPoints的长度。代码遍历了数组一次。虽然有一行sum(cardPoints[:m])和最后的sum(cardPoints),但它们都是线性操作,总体时间复杂度仍为 。
- 其中 是数组
- 空间复杂度:
- 只使用了常数个额外变量 (
n,m,count,count_min,i,left),没有使用额外的数据结构。
- 只使用了常数个额外变量 (
思考
-
逆向思维转换:
- 直接思考“从两端取”比较困难,因为组合情况多(左0右k, 左1右k-1…)。
- 转换为“中间留”则变成了标准的定长滑动窗口问题:寻找长度为
n-k的连续子数组,使其和最小。
-
边界条件修复:
- 之前的代码在
k=n时会报错IndexError。 - 原因:当
k=n时,m = n-k = 0。此时left = i - 0 + 1 = i + 1。在循环中尝试访问cardPoints[left]会导致索引越界(因为left会迅速超过数组长度)。 - 修复:添加
if k == n: return sum(cardPoints),直接处理这种极端情况。
- 之前的代码在
-
初始化技巧:
- 代码中
count_min = sum(cardPoints[:m])预先计算了第一个窗口(即数组最左边m个元素)的和。 - 这保证了即使数组中所有数字都很大,
count_min也有一个合理的初始值,而不是0或inf。
- 代码中
-
滑动窗口逻辑:
count始终维护当前遍历到的前缀和。
本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来源 笺札!






