Summer has filled her veins with light and her heart is washed with noon.
夏日使她血管里充满光,她温暖的心受午间洗沐。
问题描述
几张卡牌排成一行,每张卡牌都有一个对应的点数。点数由整数数组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
滑动窗口解决
每次拿的时候只能从开头和末尾拿,而不能从中间拿。我们换种思路,如果把数组的首尾相连,串成一个环形,那么最终拿掉的k个元素肯定是连续的,问题就转化为求k个连续元素的最大和,所以我们很容易想到的就是滑动窗口。
但这个窗口有个限制条件,就是窗口内的元素至少包含原数组首尾元素中的一个。
我们就以示例一为例来看下视频。
最后再来看下代码
1public int maxScore(int[] cardPoints, int k) { 2 int maxWindow = 0, length = cardPoints.length; 3 //先统计前k个元素的和,也是窗口内元素的和 4 for (int i = 0; i < k; i++) 5 maxWindow += cardPoints[i]; 6 //然后窗口移动,更新当前窗口的值 7 int curWindow = maxWindow; 8 for (int i = length - 1; i >= length - k; i--) { 9 //窗口移动的时候一个元素会出窗口,一个元素会进入窗口。10 //cardPoints[k - (length - i)]是移除窗口的元素11 curWindow -= cardPoints[k - (length - i)];12 //cardPoints[i]是进入窗口的元素13 curWindow += cardPoints[i];14 //记录窗口的最大值15 maxWindow = Math.max(maxWindow, curWindow);16 }17 return maxWindow;18}
总结
咋一看,无从下手,其实换个思路就很好解决了。
●542,滑动窗口解最小覆盖子串
●521,滑动窗口解最大连续1的个数 III
●443,滑动窗口最大值
●407,动态规划和滑动窗口解决最长重复子数组
截止到目前我已经写了500多道算法题了,为了方便大家阅读,我把部分算法题整理成了pdf文档,目前有1000多页,大家可以在公众号中回复关键字“pdf”即可获取下载链接。
你点的每个赞,我都认真当成了喜欢