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}


总结

咋一看,无从下手,其实换个思路就很好解决了。


549,滑动窗口解可获得的最大点数_滑动窗口

●542,滑动窗口解最小覆盖子串

●521,滑动窗口解最大连续1的个数 III

●443,滑动窗口最大值

●407,动态规划和滑动窗口解决最长重复子数组



截止到目前我已经写了500多道算法题了,为了方便大家阅读,我把部分算法题整理成了pdf文档,目前有1000多页,大家可以在公众号中回复关键字“pdf”即可获取下载链接。


549,滑动窗口解可获得的最大点数_编程开发_02你点的每个赞,我都认真当成了喜欢