🧠
Sliding Window with Last Seen Map (Fixed Window Variant)
💡 This approach uses a sliding window to maintain a window of cards without duplicates, shrinking it when duplicates appear, which is a classic sliding window pattern.
Intuition
Expand the window by moving right pointer; when a duplicate is found, move left pointer to exclude the previous occurrence, keeping the window valid and tracking minimum length.
Algorithm
- Initialize two pointers left and right at 0, and a map to track last seen indices.
- Expand right pointer over cards.
- If current card was seen and its last seen index is within the current window, move left pointer to last seen index + 1.
- Update last seen index of current card to right.
- Update minimum length with current window size when duplicates are found.
- Return minimum length or -1 if none.
💡 This algorithm dynamically adjusts the window size to maintain uniqueness and efficiently finds the minimum duplicate subarray.
def minimumCardPickup(cards):
last_seen = {}
left = 0
min_len = float('inf')
for right, card in enumerate(cards):
if card in last_seen and last_seen[card] >= left:
left = last_seen[card] + 1
last_seen[card] = right
if right - left + 1 > 1:
min_len = min(min_len, right - left + 1)
return min_len if min_len != float('inf') else -1
# Driver code
if __name__ == '__main__':
print(minimumCardPickup([3,4,2,3,4,7])) # Output: 4
print(minimumCardPickup([1,0,5,3])) # Output: -1
Line Notes
last_seen = {}Map to track last seen indices of cards
left = 0Left pointer of sliding window
if card in last_seen and last_seen[card] >= left:Check if duplicate is inside current window
left = last_seen[card] + 1Move left pointer to exclude previous duplicate
import java.util.*;
public class Main {
public static int minimumCardPickup(int[] cards) {
Map<Integer, Integer> lastSeen = new HashMap<>();
int left = 0, minLen = Integer.MAX_VALUE;
for (int right = 0; right < cards.length; right++) {
int card = cards[right];
if (lastSeen.containsKey(card) && lastSeen.get(card) >= left) {
left = lastSeen.get(card) + 1;
}
lastSeen.put(card, right);
if (right - left + 1 > 1) {
minLen = Math.min(minLen, right - left + 1);
}
}
return minLen == Integer.MAX_VALUE ? -1 : minLen;
}
public static void main(String[] args) {
System.out.println(minimumCardPickup(new int[]{3,4,2,3,4,7})); // 4
System.out.println(minimumCardPickup(new int[]{1,0,5,3})); // -1
}
}
Line Notes
Map<Integer, Integer> lastSeen = new HashMap<>();Map to track last seen indices
int left = 0, minLen = Integer.MAX_VALUE;Initialize left pointer and min length
if (lastSeen.containsKey(card) && lastSeen.get(card) >= left) {Check if duplicate inside window
left = lastSeen.get(card) + 1;Move left pointer to exclude duplicate
#include <iostream>
#include <vector>
#include <unordered_map>
#include <climits>
using namespace std;
int minimumCardPickup(vector<int>& cards) {
unordered_map<int, int> lastSeen;
int left = 0, minLen = INT_MAX;
for (int right = 0; right < (int)cards.size(); right++) {
int card = cards[right];
if (lastSeen.count(card) && lastSeen[card] >= left) {
left = lastSeen[card] + 1;
}
lastSeen[card] = right;
if (right - left + 1 > 1) {
minLen = min(minLen, right - left + 1);
}
}
return minLen == INT_MAX ? -1 : minLen;
}
int main() {
vector<int> cards1 = {3,4,2,3,4,7};
vector<int> cards2 = {1,0,5,3};
cout << minimumCardPickup(cards1) << endl; // 4
cout << minimumCardPickup(cards2) << endl; // -1
return 0;
}
Line Notes
unordered_map<int, int> lastSeen;Map to track last seen indices
int left = 0, minLen = INT_MAX;Initialize left pointer and min length
if (lastSeen.count(card) && lastSeen[card] >= left) {Check if duplicate inside current window
left = lastSeen[card] + 1;Move left pointer to exclude duplicate
function minimumCardPickup(cards) {
const lastSeen = new Map();
let left = 0, minLen = Infinity;
for (let right = 0; right < cards.length; right++) {
const card = cards[right];
if (lastSeen.has(card) && lastSeen.get(card) >= left) {
left = lastSeen.get(card) + 1;
}
lastSeen.set(card, right);
if (right - left + 1 > 1) {
minLen = Math.min(minLen, right - left + 1);
}
}
return minLen === Infinity ? -1 : minLen;
}
// Test cases
console.log(minimumCardPickup([3,4,2,3,4,7])); // 4
console.log(minimumCardPickup([1,0,5,3])); // -1
Line Notes
const lastSeen = new Map();Map to track last seen indices
let left = 0, minLen = Infinity;Initialize left pointer and min length
if (lastSeen.has(card) && lastSeen.get(card) >= left) {Check if duplicate inside window
left = lastSeen.get(card) + 1;Move left pointer to exclude duplicate
Each card is visited once; left pointer only moves forward, so total O(n) time.
💡 This approach is efficient and uses the sliding window pattern to handle duplicates dynamically.
Interview Verdict: Accepted
This is the optimal approach demonstrating sliding window mastery and is ideal for interviews.