LC-1423. 可获得的最大点数(子数组和、枚举)
1423. 可获得的最大点数
中等
几张卡牌 排成一行,每张卡牌都有一个对应的点数。点数由整数数组 cardPoints
给出。
每次行动,你可以从行的开头或者末尾拿一张卡牌,最终你必须正好拿 k
张卡牌。
你的点数就是你拿到手中的所有卡牌的点数之和。
给你一个整数数组 cardPoints
和整数 k
,请你返回可以获得的最大点数。
示例 1:
输入:cardPoints = [1,2,3,4,5,6,1], k = 3
输出:12
解释:第一次行动,不管拿哪张牌,你的点数总是 1 。但是,先拿最右边的卡牌将会最大化你的可获得点数。最优策略是拿右边的三张牌,最终点数为 1 + 6 + 5 = 12 。
示例 2:
输入:cardPoints = [2,2,2], k = 2
输出:4
解释:无论你拿起哪两张卡牌,可获得的点数总是 4 。
示例 3:
输入:cardPoints = [9,7,7,9,7,7,9], k = 7
输出:55
解释:你必须拿起所有卡牌,可以获得的点数为所有卡牌的点数之和。
示例 4:
输入:cardPoints = [1,1000,1], k = 1
输出:1
解释:你无法拿到中间那张卡牌,所以可以获得的最大点数为 1 。
示例 5:
输入:cardPoints = [1,79,80,1,1,1,200,1], k = 3
输出:202
提示:
1 <= cardPoints.length <= 10^5
1 <= cardPoints[i] <= 10^4
1 <= k <= cardPoints.length
逆向思维
https://leetcode.cn/problems/maximum-points-you-can-obtain-from-cards/solutions/2551432/liang-chong-fang-fa-ni-xiang-si-wei-zhen-e3gb/?envType=daily-question&envId=2023-12-03
class Solution {
// 逆向思维, 拿走k张,剩下n-k张,这剩下的牌一定是连续的
// 问题变成 计算长为 n-k 的连续子数组和的最小值
// 滑动窗口
public int maxScore(int[] cardPoints, int k) {
int n = cardPoints.length;
int m = n - k;
int s = 0;
for(int i = 0; i < m; i++)
s += cardPoints[i];
int total = s;
int minS = s;
for(int i = m; i < n; i++){
total += cardPoints[i];
s += cardPoints[i] - cardPoints[i-m];
minS = Math.min(minS, s);
}
return total - minS;
}
}
正向思维
class Solution {
/**
枚举所有答案值
前 k 个数的和
前 k-1 个数的以及后 1 个数的和
前 k-2 个数的以及后 2 个数的和
算法
计算前k个数的和,记作s,初始化答案 ans = s
从i = 1 开始枚举到i=k
每次枚举 把 s 增加 c[n-i] - c[k-i] 更新ans的最大值
*/
public int maxScore(int[] cardPoints, int k) {
int s = 0;
for(int i = 0; i< k; i++)
s += cardPoints[i];
int ans = s;
for(int i = 1; i <= k; i++){
s += cardPoints[cardPoints.length-i] - cardPoints[k-i];
ans = Math.max(ans, s);
}
return ans;
}
}