给定一个数组,每次只能从头和尾进行选择。
选择k次当前头或者尾,问能取到的最大值。
可获得的最大点数
主要难点是意识到这是一个滑动窗口问题。
令数组长度为 s z sz sz
令 s _ w ( p o s , k ) s\_w(pos, k) s_w(pos,k)为其实点为 p o s pos pos,长度为 k k k的滑窗。
则求解的问题为 m a x ( s u m ( s _ w ( i , k ) ) ) , ( s z − k ) ≤ i ≤ s z − 1 o r i = 0 max(sum(s\_w(i, k))),(sz-k) \le i \le sz -1 \ or\ i=0 max(sum(s_w(i,k))),(sz−k)≤i≤sz−1 or i=0
class Solution {
public:
int maxScore(vector<int>& cardPoints, int k) {
int sz = cardPoints.size();
int bpos = sz - k;
int ans = 0;
int sum = 0;
for ( int i = sz - k; i < sz - 1; ++i)
sum += cardPoints[i];
for ( int i = bpos; i < sz; ++i) {
int idx = (i + k - 1) % sz;
sum += cardPoints[idx];
ans = max(ans, sum);
sum -= cardPoints[i];
}
sum = std::accumulate(cardPoints.begin(), cardPoints.begin() + k, 0);
ans = max(sum, ans);
return ans;
}
};
直接求首尾的滑动窗口复杂点,由于数组固定则总和固定。
求最大的 S u m ( s _ w ( p o s , k ) ) Sum(s\_w(pos, k)) Sum(s_w(pos,k))可以转化为 求最小的 S u m ( s _ w ( p o w , s z − k ) ) Sum(s\_w(pow, sz -k)) Sum(s_w(pow,sz−k))。
最后再用总和减去最小的 s z − k sz-k sz−k滑窗即可。
注意:由于是首尾滑窗,所以sz-k的滑窗不能出现首尾相连情况
class Solution {
public:
int maxScore(vector<int>& cardPoints, int k) {
int sz = cardPoints.size();
int m = sz - k;
int win_sum = 0;
int tot_sum = std::accumulate(cardPoints.begin(), cardPoints.end(), 0);
if ( m == 0)
return tot_sum;
if ( m > 1) {
win_sum = std::accumulate(
cardPoints.begin(), cardPoints.begin() + m - 1,0
);
}
int win_min = INT_MAX;
for (int i = 0;i < sz - m + 1; ++i) {
int idx = (i + m - 1) % sz;
win_sum += cardPoints[idx];
win_min = min(win_min, win_sum);
win_sum -= cardPoints[i];
}
return tot_sum - win_min;
}
};
由于最终的情况无非,在前缀中取 k 1 k_1 k1,在后缀中取 k 2 k_2 k2, k 1 + k 2 = k k_1 +k_2=k k1+k2=k。
所以我们可以通过计算 P r e f i x ( i ) , 0 ≤ i ≤ k ; S u f f i x ( j ) , 0 ≤ j ≤ k Prefix(i), 0 \le i \le k;Suffix(j),0 \le j \le k Prefix(i),0≤i≤k;Suffix(j),0≤j≤k
求出每一种情况即: P r e f i x ( x ) + S u f f i x ( k − x ) Prefix(x)+Suffix(k-x) Prefix(x)+Suffix(k−x)的值来判断大小。
注意:前后缀累加只累计k轮
class Solution {
public:
int maxScore(vector<int>& cardPoints, int k) {
vector<int> prefix;
vector<int> suffix;
int preSum = 0;
int sufSum = 0;
int sz = cardPoints.size();
for ( int i = 0; i < k + 1;++i) {
prefix.push_back(preSum);
suffix.push_back(sufSum);
if ( i != k) {
preSum += cardPoints[i];
sufSum += cardPoints[sz - 1 - i];
}
}
int ans = 0;
for ( int i = 0; i < k + 1; ++i) {
ans = max(ans, prefix[i] + suffix[k - i]);
}
return ans;
}
};