1423. Maximum Points You Can Obtain From Cards - Explanation
Description
There are several cards arranged in a row, and each card has an associated number of points. The points are given in the integer array cardPoints.
In one step, you can take one card from the beginning or from the end of the row. You have to take exactly k cards.
Your score is the sum of the points of the cards you have taken.
Given the integer array cardPoints and the integer k, return the maximum score you can obtain.
Example 1:
Input: cardPoints = [1,2,3,4,5,6,1], k = 3
Output: 12Explanation: After the first step, your score will always be 1. However, choosing the rightmost card first will maximize your total score. The optimal strategy is to take the three cards on the right, giving a final score of 1 + 6 + 5 = 12.
Example 2:
Input: cardPoints = [2,2,2], k = 2
Output: 4Explanation: Regardless of which two cards you take, your score will always be 4.
Example 3:
Input: cardPoints = [9,7,7,9,7,7,9], k = 7
Output: 55Explanation: You have to take all the cards. Your score is the sum of points of all cards.
Constraints:
1 <= k <= cardPoints.length <= 100,0001 <= cardPoints[i] <= 10,000
Topics
Prerequisites
Before attempting this problem, you should be comfortable with:
- Sliding Window Technique - The key insight is that picking k cards from ends leaves a contiguous window of n-k cards
- Prefix and Suffix Sums - Used to compute sums of left and right segments in constant time
- Two Pointers - The optimal solution slides a virtual window that wraps around the array ends
1. Brute Force
Intuition
Since we can only take cards from the beginning or end, any valid selection forms two contiguous segments: one from the left and one from the right, totaling k cards. We can try all possible splits: take 0 from left and k from right, take 1 from left and k-1 from right, and so on.
Algorithm
- For each split
leftfrom0tok:- Compute the sum of the first
leftcards. - Compute the sum of the last
k - leftcards. - Track the maximum total.
- Compute the sum of the first
- Return the maximum sum found.
Time & Space Complexity
- Time complexity:
- Space complexity: extra space.
Where is the number of cards to pick.
2. Prefix & Suffix Sums
Intuition
Instead of recomputing sums for each split, we precompute prefix sums (sums from the left) and suffix sums (sums from the right). Then for any split, we can get the total in constant time by combining the appropriate prefix and suffix values.
Algorithm
- Build a prefix sum array where
prefix[i]is the sum of the firsticards. - Build a suffix sum array where
suffix[i]is the sum of cards from indexito the end. - For each split taking
leftcards from the front andk - leftfrom the back:- Total =
prefix[left] + suffix[n - (k - left)]. - Track the maximum.
- Total =
- Return the maximum sum.
class Solution:
def maxScore(self, cardPoints: List[int], k: int) -> int:
n = len(cardPoints)
prefix = [0] * (n + 1)
for i in range(n):
prefix[i + 1] = prefix[i] + cardPoints[i]
suffix = [0] * (n + 1)
for i in range(n - 1, -1, -1):
suffix[i] = suffix[i + 1] + cardPoints[i]
res = 0
for left in range(k + 1):
right = k - left
res = max(res, prefix[left] + suffix[n - right])
return resTime & Space Complexity
- Time complexity:
- Space complexity:
3. Sliding Window (Minimum Sum Window)
Intuition
If we pick k cards total from the ends, we leave behind a contiguous subarray of size n - k in the middle. Maximizing the sum of picked cards is equivalent to minimizing the sum of the remaining window. We slide a window of size n - k across the array and find its minimum sum.
Algorithm
- Calculate the window size as
n - k. - If the window size is
0, return the total sum of all cards. - Slide a window of this size across the array, tracking the minimum window sum.
- The answer is the total sum minus this minimum window sum.
class Solution:
def maxScore(self, cardPoints: List[int], k: int) -> int:
n = len(cardPoints)
windowSize = n - k
if windowSize == 0:
return sum(cardPoints)
total = 0
minWindowSum = float("inf")
curSum = 0
for i in range(n):
total += cardPoints[i]
curSum += cardPoints[i]
if i >= windowSize - 1:
minWindowSum = min(minWindowSum, curSum)
curSum -= cardPoints[i - windowSize + 1]
return total - minWindowSumTime & Space Complexity
- Time complexity:
- Space complexity: extra space.
4. Sliding Window
Intuition
We can directly maintain a sliding window of size k that wraps around the array. Start by taking all k cards from the right end. Then slide the window: remove one card from the right and add one from the left, tracking the maximum sum as we go.
Algorithm
- Initialize the sum by taking the last
kcards (all from the right). - Use two pointers:
lstarting at0,rstarting atn - k. - Slide the window
ktimes:- Add
cardPoints[l]and subtractcardPoints[r]. - Update the maximum sum.
- Move both pointers forward.
- Add
- Return the maximum sum found.
Time & Space Complexity
- Time complexity:
- Space complexity: extra space.
Where is the number of cards to pick.
Common Pitfalls
Treating This as a Standard Two-Pointer Problem
Unlike typical two-pointer problems where pointers move toward each other, this problem requires taking cards from both ends that together form a contiguous "virtual" window. The cards you pick are not contiguous in the original array, which confuses many solvers into incorrect pointer movement logic.
Off-by-One Errors in Window Boundaries
When using the sliding window approach (finding minimum sum of n - k elements), incorrect boundary calculations are common. The window size is n - k, not k. Additionally, when indexing the right portion of the array, using n - right instead of the correct index offset leads to accessing wrong elements.
Forgetting the Edge Case When k Equals n
When k equals the array length, you must take all cards. The sliding window approach would have a window of size 0, which needs special handling to avoid division by zero or invalid array access. Simply return the total sum when k == n.
Sign in to join the discussion