Want Help Cracking FAANG?

(Then click this)

×
Back to Question Bank

1127. User Purchase Platform - Leetcode Solution

Problem Description

The User Purchase Platform problem on LeetCode provides you with a set of user purchase records and asks you to analyze user purchasing behavior. Typically, you are given a list of users, their purchases (with timestamps and amounts), and possibly the platform (like 'web', 'mobile', etc.) from which the purchase was made.

The task is usually to answer questions like: Which users made purchases on multiple platforms? or Which users made their first purchase on the mobile platform? or For each user, return their earliest purchase per platform.

Constraints often include:

  • Each purchase record contains a user_id, purchase_time, platform, and amount.
  • There may be multiple purchases per user and per platform.
  • You may need to aggregate or filter based on earliest/latest purchase, unique platform count, or similar analytics.
Note: For this explanation, we'll assume the question is: Return the list of users who have made purchases on at least two different platforms.

Thought Process

To solve this problem, we need to identify users who have made purchases on more than one platform. The straightforward (brute-force) approach would be to, for each user, collect all the platforms they have used and count them. If a user's platform count is two or more, include them in the result.

The brute-force way would involve iterating through all records, grouping by user, and counting unique platforms. However, this can be inefficient for large datasets.

To optimize, we can use a hash map (dictionary) to map each user to a set of platforms they've used. This allows us to efficiently add platforms and check the count at the end.

This approach is analogous to making a list of all the stores you've shopped at: for each receipt, add the store to your list if it's not there already. At the end, count how many unique stores you have for each person.

Solution Approach

Let's break down the solution step by step:

  1. Initialize a hash map: Create a dictionary (or map) where each key is a user_id and the value is a set of platforms the user has made purchases on.
  2. Process each purchase record: For every purchase, add the platform to the corresponding user's set in the map. Using a set ensures we only store unique platforms per user.
  3. Filter users: After processing all records, iterate over the map and collect users who have two or more platforms in their set.
  4. Return the result: Output the list of user IDs (possibly sorted, depending on requirements).

We use a set for each user because checking for uniqueness and adding a new platform is an O(1) operation, and avoids counting duplicate platforms.

Example Walkthrough

Consider the following purchase records:

  • User 1, "2024-06-01", "web", $20
  • User 1, "2024-06-02", "mobile", $30
  • User 2, "2024-06-01", "web", $25
  • User 2, "2024-06-03", "web", $15
  • User 3, "2024-06-02", "mobile", $40
  • User 3, "2024-06-03", "mobile", $50

Step by step:

  • For User 1: platforms = {"web"} (after first record), then {"web", "mobile"} (after second record)
  • For User 2: platforms = {"web"} (both records)
  • For User 3: platforms = {"mobile"} (both records)
At the end:
  • User 1: 2 platforms ("web", "mobile")
  • User 2: 1 platform ("web")
  • User 3: 1 platform ("mobile")
Result: Only User 1 has made purchases on at least two different platforms.

Time and Space Complexity

Brute-force Approach:

  • Time Complexity: O(N * P), where N is the number of users and P is the number of platforms. For each user, you might have to check all their purchases and all possible platforms.
  • Space Complexity: O(N * P), as you may need to store all platforms for all users.
Optimized Approach (with Hash Map and Sets):
  • Time Complexity: O(M), where M is the total number of purchase records. Each record is processed once, and set operations are O(1).
  • Space Complexity: O(N * P), where N is the number of users and P is the average number of unique platforms per user.

The optimized approach is much more efficient, especially for large datasets.

Summary

In this problem, we efficiently identified users who made purchases on at least two different platforms by leveraging a hash map with sets to track unique platforms per user. This strategy avoids unnecessary repeated work and allows for quick lookups and insertions. The key insight is to use data structures that fit the problem's requirements, leading to a clean and performant solution.

Code Implementation

from collections import defaultdict
from typing import List, Dict

def users_with_multiple_platforms(purchases: List[Dict]) -> List[int]:
    # purchases: List of dicts with keys: user_id, purchase_time, platform, amount
    user_platforms = defaultdict(set)
    for purchase in purchases:
        user_platforms[purchase['user_id']].add(purchase['platform'])
    result = [user_id for user_id, platforms in user_platforms.items() if len(platforms) >= 2]
    return sorted(result)
      
#include <vector>
#include <string>
#include <unordered_map>
#include <unordered_set>
#include <algorithm>

using namespace std;

struct Purchase {
    int user_id;
    string purchase_time;
    string platform;
    double amount;
};

vector<int> usersWithMultiplePlatforms(const vector<Purchase>& purchases) {
    unordered_map<int, unordered_set<string>> userPlatforms;
    for (const auto& p : purchases) {
        userPlatforms[p.user_id].insert(p.platform);
    }
    vector<int> result;
    for (const auto& entry : userPlatforms) {
        if (entry.second.size() >= 2) {
            result.push_back(entry.first);
        }
    }
    sort(result.begin(), result.end());
    return result;
}
      
import java.util.*;

class Purchase {
    int userId;
    String purchaseTime;
    String platform;
    double amount;
    public Purchase(int userId, String purchaseTime, String platform, double amount) {
        this.userId = userId;
        this.purchaseTime = purchaseTime;
        this.platform = platform;
        this.amount = amount;
    }
}

public class Solution {
    public List<Integer> usersWithMultiplePlatforms(List<Purchase> purchases) {
        Map<Integer, Set<String>> userPlatforms = new HashMap<>();
        for (Purchase p : purchases) {
            userPlatforms
                .computeIfAbsent(p.userId, k -> new HashSet<>())
                .add(p.platform);
        }
        List<Integer> result = new ArrayList<>();
        for (Map.Entry<Integer, Set<String>> entry : userPlatforms.entrySet()) {
            if (entry.getValue().size() >= 2) {
                result.add(entry.getKey());
            }
        }
        Collections.sort(result);
        return result;
    }
}
      
function usersWithMultiplePlatforms(purchases) {
    // purchases: Array of objects {user_id, purchase_time, platform, amount}
    const userPlatforms = {};
    purchases.forEach(purchase => {
        if (!userPlatforms[purchase.user_id]) {
            userPlatforms[purchase.user_id] = new Set();
        }
        userPlatforms[purchase.user_id].add(purchase.platform);
    });
    const result = [];
    for (const userId in userPlatforms) {
        if (userPlatforms[userId].size >= 2) {
            result.push(Number(userId));
        }
    }
    return result.sort((a, b) => a - b);
}