题目:
几张卡牌 排成一行,每张卡牌都有一个对应的点数。点数由整数数组 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
解题思路
首先这里每次可以从队尾或者队前拿取一个,因为需要值最大,那么怎么确保这个取得的数呢?
首先我们肯定最常用想法就是判断队尾或者队前哪一个大选择取队尾或者队前。这样初略一想好像是这么一回事。
但是这个肯定是不对的: 数据为 1 1 200 5 3 2 4
这样按照上面逻辑当k=3时,实现肯定就是4+2+3,这样就会出现错误,这里最大的肯定是202.
那么我们如何考虑可以避免这个情况呢?在这里是不是想要取得这个数肯定是会取前面两个数的。那么我们这么思考,首先,我们从队尾或者队前直接顺序取k个数,然后再进行依次取右侧然后将和剩下的部分的和,取最大值结果
也就是这么个理解:
例如 2 5 6 7 8 9 10 5 10 3 k=4
首先我们直接取前k个数:
那么就是2+5+6+7=20
那么下面我们进行什么操作呢
就是20减去取得的最后一个数20-7然后再加上队尾的最后一个数,所以就是20-7+3=16
然后拿这个数据和临时标记的最大值进行对比
后面就是依次再减去倒数第2个数20-7-6=7(这里是依次递减可以用上一个数直接减去6,为方便理解故此写出来),再用这个数加队尾的两个数7+3+10=20,与临时标记的最大值进行对比,如果大于最大值则替换反之继续遍历
再就依次递推第三个数:20-7-6-5=2,那么再用2+3+10+5=20,与临时标记的最大值进行对比,如果大于最大值则替换反之继续遍历
继续:20-7-6-5-2=0,后面0+3+10+5+10=28,这里就是最大值28.
实现代码:
class Solution {
public int maxScore(int[] cardPoints, int k) {
int n = cardPoints.length-1;
int sum = 0;
for (int i = 0; i < k; i++) {
sum += cardPoints[i];//这里直接取前k个数,当然这里也可以修改为取后k个数,后面进行对应的修改即可
}
int max = sum;//临时标记最大值k
for (int i = 0; i < k; i++) {
sum = sum - cardPoints[k - 1 - i] + cardPoints[n - i];//减去前面数组的值对应加队尾的值
max = Math.max(max, sum);
}
return max;
}
}