2260. Minimum Consecutive Cards to Pick Up
Problem Description
In this problem, you're given an array cards
with each element representing the value of a card. The task is to find the minimum number of consecutive cards you need to pick from the array to get a pair of matching cards (i.e., two cards with the same value). If it is possible to get a matching pair by picking cards consecutively, you should return the minimum number of cards you need to pick. If no matching pairs exist in the sequence of cards, the function should return -1
.
Intuition
To solve this problem, we can utilize a HashMap to keep track of the last seen indices of card values. As we iterate over the array of cards, we check if the current card's value has already been seen before by consulting the HashMap. If it has been seen before, we subtract the previous index where this value was seen from the current index to find the distance between them, which also includes the currently picked card (hence we add 1). We continuously update the minimum distance whenever we find a pair of matching cards.
- Start by initializing a HashMap
last
to store the last index where each card value was seen. - Initialize a variable
ans
to store the answer, initialized toinf
(infinity), which represents that the initial distance is infinitely large. - Iterate over the cards array using an index
i
and the card valuex
: a. If the cardx
is already in the HashMap (last
), it means a previous card with the same value was seen. Therefore, calculate the distance from the current card to the last card with the same value, which can be done byi - last[x] + 1
, and update the answerans
by the minimum of the current answer and this new distance. b. Update thelast
HashMap to mark the current indexi
as the latest index at which the card valuex
was seen. - After the loop, check if
ans
is stillinf
. If it is, that means no matching cards were found, and you should return-1
. Otherwise, returnans
as the minimum number of consecutive cards to pick up to have a pair of matching cards.
The strength of this approach lies in its time complexity. Because the HashMap access/update is O(1)
on average and the iteration of the cards is O(n)
where n
is the number of cards, the overall time complexity of this approach is O(n)
which is efficient.
Learn more about Sliding Window patterns.
Solution Approach
The solution uses a simple yet effective algorithm combined with a dictionary (a.k.a. HashMap in other languages) data structure to efficiently track the last occurrence index of card values.
Here's a walkthrough of the code implementation:
- A dictionary named
last
is created to store the last occurrence index of each card value encountered as we iterate over the array. - A variable named
ans
is initialized withinf
, which represents infinity. This variable will eventually hold the minimum number of cards required to find a matching pair or stay as infinity if no match is found. - The code then iterates over each card in the
cards
array using afor
loop with the indexi
and card valuex
.- If the card value
x
is found in thelast
dictionary, this implies that we have encountered this value before, and therefore, we have found a pair of matching cards. The current distance to the last seen matching card is calculated byi - last[x] + 1
.+1
is included because both the current card and the last card are part of the set we are considering. We then updateans
with the minimum of its current value and the newly calculated distance. - Whether a match is found or not, the
last
dictionary is updated such thatx
now points to the current indexi
. This operation ensures that the next timex
is encountered, the distance will be calculated from this point.
- If the card value
- After the loop concludes, the
ans
variable is checked to determine whether it still containsinf
(meaning no pairs were found). Ifans
is stillinf
, the function returns-1
, as it is not possible to have matching cards. Otherwise, it returns the value ofans
, which is the minimum number of consecutive cards needed to pick up to get a matching pair.
The efficiency of the algorithm comes from the use of the last
dictionary, which allows constant time lookup and update for the indices of card values. This means that the algorithm will perform well, even for large arrays, as the time complexity remains linear (O(n)
), where n
is the number of cards.
Ready to land your dream job?
Unlock your dream job with a 2-minute evaluator for a personalized learning plan!
Start EvaluatorExample Walkthrough
To illustrate the solution approach, let's consider a small example using the array of cards: [5, 1, 3, 4, 5, 6, 7, 3]
.
- We start with an empty dictionary
last
and initializeans
toinf
. - Iteration 1: Card value is
5
. Since5
is not present in the dictionarylast
, we add it tolast
with index0
:last[5] = 0
. - Iteration 2: Card value is
1
. It's also not inlast
, thus we addlast[1] = 1
. - Iteration 3: Card value is
3
. We add it tolast
:last[3] = 2
. - Iteration 4: Card value is
4
. We addlast[4] = 3
. - Iteration 5: Card value is
5
. This time,5
is already inlast
with the index0
. We calculate the distance:i - last[5] + 1 = 5 - 0 + 1 = 6
. We then updateans
to6
since6 < inf
. We also updatelast[5]
to the current index:last[5] = 4
. - Iteration 6: Card value is
6
. We addlast[6] = 5
. - Iteration 7: Card value is
7
. We addlast[7] = 6
. - Iteration 8: Card value is
3
. As3
is inlast
with the index2
, we find another pair. We calculate the distance:i - last[3] + 1 = 8 - 2 + 1 = 7
. We compare this with the currentans
, which is6
, and since7
is larger, we don't updateans
. Updatelast[3] = 7
.
After the iterations, the smallest value in ans
that was updated is 6
. Therefore, the minimum number of consecutive cards you need to pick up to get a pair of matching cards is 6
.
In contrast, if our cards array was something like [8, 5, 1, 3, 4]
where no values repeat, at the end of our iteration, the ans
would still be inf
, and we would return -1
since there are no consecutive cards that form a pair.
Solution Implementation
1from math import inf
2
3class Solution:
4 def minimumCardPickup(self, cards: List[int]) -> int:
5 # Create a dictionary to keep track of the last index where each card was seen.
6 last_seen = {}
7 # Initialize the answer to infinity to represent a large number.
8 min_pickup_length = inf
9
10 # Iterate over the list of cards with their indices.
11 for index, card_value in enumerate(cards):
12 # If the card was seen before, calculate the pickup length.
13 if card_value in last_seen:
14 # Update the minimum pickup length if a shorter one is found.
15 min_pickup_length = min(min_pickup_length, index - last_seen[card_value] + 1)
16 # Update the last seen index for the current card.
17 last_seen[card_value] = index
18
19 # Return -1 if the answer remains infinity (no pickup found), else return the minimum pickup length.
20 return -1 if min_pickup_length == inf else min_pickup_length
21
1class Solution {
2 public int minimumCardPickup(int[] cards) {
3 // Create a map to store the last index of each card value
4 Map<Integer, Integer> lastIndexMap = new HashMap<>();
5 int numOfCards = cards.length;
6 // Initialize the smallest sequence length to maximum possible value
7 int minSequenceLength = numOfCards + 1;
8
9 // Iterate through each card in the array
10 for (int i = 0; i < numOfCards; ++i) {
11 // If the current card has been seen before...
12 if (lastIndexMap.containsKey(cards[i])) {
13 // Update the smallest sequence length with the minimum between
14 // the current smallest sequence length and
15 // the length of the current sequence of cards
16 minSequenceLength = Math.min(minSequenceLength, i - lastIndexMap.get(cards[i]) + 1);
17 }
18 // Update the last index for this card value
19 lastIndexMap.put(cards[i], i);
20 }
21
22 // If no sequence is found (minSequenceLength was not updated), return -1
23 // Otherwise, return the smallest sequence length
24 return minSequenceLength > numOfCards ? -1 : minSequenceLength;
25 }
26}
27
1#include <vector>
2#include <unordered_map>
3#include <algorithm>
4
5class Solution {
6public:
7 // Function to find the minimum number of cards to be picked up in order
8 // to get a pair of cards with the same value.
9 int minimumCardPickup(vector<int>& cards) {
10 unordered_map<int, int> lastIndex; // Stores the last index where each card was seen
11 int n = cards.size(); // The number of cards
12 int minPickup = n + 1; // Initialize it to an impossible maximum
13
14 // Iterate over the cards
15 for (int i = 0; i < n; ++i) {
16 // If we have seen cards[i] before, calculate the distance from its last occurrence
17 if (lastIndex.count(cards[i])) {
18 minPickup = min(minPickup, i - lastIndex[cards[i]] + 1);
19 }
20 // Update the last seen index of cards[i]
21 lastIndex[cards[i]] = i;
22 }
23
24 // If minPickup did not change from its initial value, no pair was found; return -1
25 // Otherwise, return the minimum number of cards picked up to find a pair
26 return minPickup > n ? -1 : minPickup;
27 }
28};
29
1function minimumCardPickup(cards: number[]): number {
2 // Store the length of the cards array.
3 const cardCount = cards.length;
4 // Create a new map to store the last occurrence index of each card.
5 const lastIndexMap = new Map<number, number>();
6 // Initialize the answer to be larger than any possible minimum pickup length.
7 let minPickupLength = cardCount + 1;
8 // Iterate through the cards.
9 for (let index = 0; index < cardCount; ++index) {
10 // Check if we have seen the current card before.
11 if (lastIndexMap.has(cards[index])) {
12 // Update the minimum pickup length if we've found a shorter subarray.
13 minPickupLength = Math.min(minPickupLength, index - lastIndexMap.get(cards[index])! + 1);
14 }
15 // Update the map with the latest index of the current card.
16 lastIndexMap.set(cards[index], index);
17 }
18 // If the answer is still larger than any possible value, return -1 as no valid subarray was found.
19 return minPickupLength > cardCount ? -1 : minPickupLength;
20}
21
Time and Space Complexity
Time Complexity
The time complexity of the provided code is O(n)
, where n
is the number of cards. This is because the code iterates through the list of cards exactly once with a single loop (for i, x in enumerate(cards):
). Within this loop, checking if x
is in last
(if x in last:
) and updating last[x]
(last[x] = i
) are both operations that take O(1)
time on average when using a dictionary in Python.
Space Complexity
The space complexity of the provided code is O(u)
, where u
is the number of unique cards. This is because a dictionary last
is used to store the last index at which each card appears. In the worst-case scenario where all card values are unique, the dictionary would need to store an entry for each card, thus requiring O(u)
space.
Learn more about how to find time and space complexity quickly using problem constraints.
What data structure does Breadth-first search typically uses to store intermediate states?
Recommended Readings
https algomonster s3 us east 2 amazonaws com cover_photos stack svg Sliding Window Maximum Monotonic Stack We have an array and a sliding window defined by a start index and an end index The sliding window moves from left of the array to right There are always k elements in
LeetCode Patterns Your Personal Dijkstra's Algorithm to Landing Your Dream Job The goal of AlgoMonster is to help you get a job in the shortest amount of time possible in a data driven way We compiled datasets of tech interview problems and broke them down by patterns This way we
Recursion Recursion is one of the most important concepts in computer science Simply speaking recursion is the process of a function calling itself Using a real life analogy imagine a scenario where you invite your friends to lunch https algomonster s3 us east 2 amazonaws com recursion jpg You first
Want a Structured Path to Master System Design Too? Don’t Miss This!