1. 题意
给定一个数组,每次只能从头和尾进行选择。
选择k次当前头或者尾,问能取到的最大值。
可获得的最大点数
2. 题解
主要难点是意识到这是一个滑动窗口问题。
2.1 滑动窗口
令数组长度为
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
- 正向
T i m e : O ( k ) , S p a c e : O ( 1 ) Time:O(k),Space: O(1) Time:O(k),Space:O(1)
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的滑窗不能出现首尾相连情况
- 逆向
T i m e : O ( n ) , S p a c e : O ( 1 ) Time:O(n),Space: O(1) Time:O(n),Space:O(1)
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;
}
};
2.2 前缀和与后缀和
由于最终的情况无非,在前缀中取
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)的值来判断大小。
- 前后缀分解
T i m e : O ( k ) , S p a c e : O ( k ) Time:O(k),Space: O(k) Time:O(k),Space:O(k)
注意:前后缀累加只累计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;
}
};