Skip to content

Commit eff6568

Browse files
committed
feat(algorithms, sliding-window): max points from cards
1 parent 4f77531 commit eff6568

26 files changed

+163
-1
lines changed
Lines changed: 101 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,101 @@
1+
# Max Points You Can Obtain From Cards
2+
3+
Given an array of integers representing card values, write a function to calculate the maximum score you can achieve by
4+
picking exactly k cards.
5+
6+
You must pick cards in order from either end. You can take some cards from the beginning, then switch to taking cards
7+
from the end, but you cannot skip cards or pick from the middle.
8+
9+
For example, with k = 3:
10+
11+
- Take the first 3 cards: valid
12+
- Take the last 3 cards: valid
13+
- Take the first card, then the last 2 cards: valid
14+
- Take the first 2 cards, then the last card: valid
15+
- Take card at index 0, skip some, then take card at index 5: not valid (skipping cards)
16+
17+
## Constraints
18+
19+
- 1 <= k <= cards.length
20+
- 1 <= `cards.length` <= 10^5
21+
- 1 <= `cards[i]` <= 10^4
22+
23+
## Examples
24+
25+
Example 1:
26+
```text
27+
Input: cardPoints = [1,2,3,4,5,6,1], k = 3
28+
Output: 12
29+
Explanation: After the first step, your score will always be 1. However, choosing the rightmost card first will maximize
30+
your total score. The optimal strategy is to take the three cards on the right, giving a final score of 1 + 6 + 5 = 12.
31+
```
32+
33+
Example 2:
34+
```text
35+
Input: cardPoints = [2,2,2], k = 2
36+
Output: 4
37+
Explanation: Regardless of which two cards you take, your score will always be 4.
38+
```
39+
40+
Example 3:
41+
```text
42+
Input: cardPoints = [9,7,7,9,7,7,9], k = 7
43+
Output: 55
44+
Explanation: You have to take all the cards. Your score is the sum of points of all cards.
45+
```
46+
47+
## Topics
48+
49+
- Array
50+
- Sliding Window
51+
- Prefix Sum
52+
53+
## Solutions
54+
55+
When you pick k cards from either end of the array, you're actually leaving behind n - k consecutive cards in the middle
56+
that you didn't pick.
57+
58+
For example, with cards = [2,11,4,5,3,9,2] and k = 3:
59+
60+
![Solution 1](./images/solutions/max_points_from_cards_solution_1.png)
61+
62+
Every possible way to pick 3 cards from the ends corresponds to a different window of 4 cards (n - k = 7 - 3 = 4) in the
63+
middle that we're NOT picking.
64+
65+
### Why This Matters
66+
67+
Since we know the total sum of all cards, we can calculate:
68+
69+
Sum of picked cards = Total sum - Sum of unpicked cards
70+
71+
So to maximize the sum of picked cards, we need to minimize the sum of unpicked cards.
72+
73+
This transforms the problem: instead of trying all combinations of picking from ends, we find the minimum sum of any
74+
window of size n - k.
75+
76+
![Solution 2](./images/solutions/max_points_from_cards_solution_2.png)
77+
78+
### Algorithm
79+
80+
Use a fixed-length sliding window of size n - k to find the minimum sum of any consecutive n - k cards. For each window
81+
position, calculate total - window_sum to get the corresponding score, and track the maximum.
82+
83+
![Solution 3](./images/solutions/max_points_from_cards_solution_3.png)
84+
![Solution 4](./images/solutions/max_points_from_cards_solution_4.png)
85+
![Solution 5](./images/solutions/max_points_from_cards_solution_5.png)
86+
![Solution 6](./images/solutions/max_points_from_cards_solution_6.png)
87+
![Solution 7](./images/solutions/max_points_from_cards_solution_7.png)
88+
![Solution 8](./images/solutions/max_points_from_cards_solution_8.png)
89+
![Solution 9](./images/solutions/max_points_from_cards_solution_9.png)
90+
![Solution 10](./images/solutions/max_points_from_cards_solution_10.png)
91+
![Solution 11](./images/solutions/max_points_from_cards_solution_11.png)
92+
![Solution 12](./images/solutions/max_points_from_cards_solution_12.png)
93+
![Solution 13](./images/solutions/max_points_from_cards_solution_13.png)
94+
![Solution 14](./images/solutions/max_points_from_cards_solution_14.png)
95+
![Solution 15](./images/solutions/max_points_from_cards_solution_15.png)
96+
![Solution 16](./images/solutions/max_points_from_cards_solution_16.png)
97+
![Solution 17](./images/solutions/max_points_from_cards_solution_17.png)
98+
![Solution 18](./images/solutions/max_points_from_cards_solution_18.png)
99+
![Solution 19](./images/solutions/max_points_from_cards_solution_19.png)
100+
![Solution 20](./images/solutions/max_points_from_cards_solution_20.png)
101+
![Solution 21](./images/solutions/max_points_from_cards_solution_21.png)
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
from typing import List
2+
3+
4+
def max_score(card_points: List[int], k: int) -> int:
5+
number_of_cards = len(card_points)
6+
total_points = sum(card_points)
7+
8+
# If we have to pick all the cards or more cards that we have been provided with, then the max score is the total
9+
# of all the cards
10+
if k >= number_of_cards:
11+
return total_points
12+
13+
# Maintain a state or the window sum to calculate the sum of the cards in the window
14+
window_sum = 0
15+
# Max points is the score we get from the cards we pick, this is what we eventually return
16+
max_points = 0
17+
# This will keep track of the index of the card to remove from the current window as we traverse the cards
18+
start = 0
19+
20+
for end in range(number_of_cards):
21+
# Add the card at the end of the window to the window sum
22+
window_sum += card_points[end]
23+
24+
# Calculates if we have a valid window to calculate the max points
25+
if end - start + 1 == number_of_cards - k:
26+
max_points = max(max_points, total_points - window_sum)
27+
# Contract the window, by removing the card at the start of the window
28+
window_sum -= card_points[start]
29+
# Move to the next index
30+
start += 1
31+
32+
return max_points
69.1 KB
Loading
44.5 KB
Loading
48.2 KB
Loading
44.3 KB
Loading
45.1 KB
Loading
47.2 KB
Loading
49 KB
Loading
45.4 KB
Loading

0 commit comments

Comments
 (0)