Example 1
ready- Input
cardPoints = [ 1, 2, 3, 4, 5, 6, 1 ] k = 3- Expected
12- Why
- take the final three cards from the back: 5 + 6 + 1 = 12
A row of reward cards sits face up, but you can reach only its two ends. A valuable card in the middle becomes reachable only after the cards in front of it are gone.
Given an array cardPoints and an integer k, take exactly k cards. Each move removes
either the front card or the back card from the remaining row. Return the largest total
score you can collect.
A few ground rules:
k cards, not up to k.1_000_000_000, so it fits a signed 32-bit integer.1 <= cardPoints.length <= 100_0001 <= cardPoints[i] <= 10_0001 <= k <= cardPoints.lengthHints
If you take i cards from the front, the other k - i must come from the back.
That leaves only k + 1 front/back splits to compare.
After removing cards only from the two ends, every card you leave behind forms one
unbroken interior block. Its length is cardPoints.length - k.
Your score equals the total of all cards minus the sum of that interior block. Find
the minimum-sum fixed window of length n - k, then subtract it from the total.
Can you evaluate all k + 1 front/back splits in O(k) time while keeping only O(1)
extra space? Which formulation does less work when k is tiny compared with the row?
Visible cases
cardPoints = [
1,
2,
3,
4,
5,
6,
1
]
k = 312cardPoints = [
2,
2,
2
]
k = 36cardPoints = [
9,
1,
1,
9
]
k = 218cardPoints = [
5,
4,
3,
2,
1
]
k = 29Interview signal
Any legal result takes some number i from the front and the remaining k - i from
the back. Build cumulative totals for both ends, then score every i from 0 through
k.
def max_points_cards(card_points: list[int], k: int) -> int:
front = [0] * (k + 1)
back = [0] * (k + 1)
for count in range(1, k + 1):
front[count] = front[count - 1] + card_points[count - 1]
back[count] = back[count - 1] + card_points[-count]
best = 0
for take_front in range(k + 1):
take_back = k - take_front
best = max(best, front[take_front] + back[take_back])
return bestThe loop includes both extremes: take everything from the back when take_front == 0,
and everything from the front when take_front == k.
Time O(k) — build two length-k totals and test k + 1 splits. Space O(k) for
the prefix and suffix totals.
Reverse your point of view. Taking k cards from the two ends leaves exactly
n - k neighboring cards in the middle. Since
taken score = total score - leftover score, maximizing what you take is the same as
minimizing that fixed-size leftover window.
def max_points_cards(card_points: list[int], k: int) -> int:
total = 0
for points in card_points:
total += points
interior_size = len(card_points) - k
if interior_size == 0:
return total
interior_sum = 0
for i in range(interior_size):
interior_sum += card_points[i]
min_interior = interior_sum
for right in range(interior_size, len(card_points)):
interior_sum += card_points[right]
interior_sum -= card_points[right - interior_size]
min_interior = min(min_interior, interior_sum)
return total - min_interiorEvery legal front/back choice corresponds to one interior window, including an empty
one when k == n. Checking every interior window therefore checks every possible score.
Time O(n) — total the row and slide across it once. Space O(1) — only the total, current interior sum, and minimum are stored.
The split method can touch fewer cards when k is small; the interior method earns its
place here because it exposes the fixed-window transformation without allocating arrays.
Ready to run.
4 cases are queued.
Visible testcase
Case 1
Expected
12