Want Help Cracking FAANG?

(Then click this)

×
Back to Question Bank

1817. Finding the Users Active Minutes - Leetcode Solution

Problem Description

The "Finding the Users Active Minutes" problem asks you to analyze user activity logs and summarize each user's unique activity minutes. Given a list of activity records, where each record contains a userID and a minute value, you need to find out, for each possible value of k (from 1 to k), how many users had exactly k unique active minutes (UAM).

  • The input is a list of integer pairs logs, where logs[i] = [userID, minute]. Each pair means that user userID was active at minute minute.
  • You are also given an integer k.
  • For each i from 1 to k, you must return the number of users whose count of unique active minutes is exactly i.
  • The answer should be an array answer of length k, where answer[i-1] is the number of users with exactly i unique active minutes.

Key constraints:

  • Each userID and minute is an integer.
  • There may be duplicate logs for the same user and minute (these should only count once toward unique active minutes).
  • Each user counts only for their number of unique minutes, not total logs.

Thought Process

At first glance, it might seem like we can simply count the number of logs for each user. However, since a user can have multiple logs in the same minute, we need to count only unique minutes for each user.

The brute-force approach would be to, for each user, scan through all logs and collect their unique minutes. But this would be inefficient for large inputs.

To optimize, we can use a data structure that allows us to efficiently record and count unique minutes for each user, such as a set for each user. Once we have the unique minutes for every user, we can count how many users had exactly 1, 2, ..., k unique active minutes.

The shift from brute-force to optimization comes from using a hash map (dictionary) to map each user to a set of their unique minutes, and then using another array to tally the counts.

Solution Approach

Let's break down the solution into clear steps:

  1. Track unique minutes for each user:
    • Create a hash map (dictionary) where the keys are userID and the values are sets of unique minutes.
    • Iterate through each log entry and add the minute to the corresponding user's set.
  2. Count users by their unique minute count:
    • Create an array answer of length k initialized with zeros.
    • For each user, determine how many unique minutes they have (i.e., the size of their set).
    • If the count is between 1 and k (inclusive), increment answer[count - 1] by 1.
  3. Return the result:
    • Return the answer array.

Why these choices?

  • Using a set for each user ensures that duplicate minutes are not counted more than once.
  • A hash map provides O(1) average time for lookups and insertions.
  • The final array is direct and efficient for counting and returning the results.

Example Walkthrough

Sample Input:

logs = [[0,5],[1,2],[0,2],[0,5],[1,3]]
k = 5
    

  1. Step 1: Build user-minute sets
    • User 0: minutes = {2, 5} (from logs [0,5], [0,2], [0,5])
    • User 1: minutes = {2, 3} (from logs [1,2], [1,3])
  2. Step 2: Count unique minutes for each user
    • User 0: 2 unique minutes
    • User 1: 2 unique minutes
  3. Step 3: Tally the results
    • answer[1] (users with 2 UAM): incremented twice (for both users)
    • Final answer array: [0, 2, 0, 0, 0]

Explanation:
There are 0 users with 1 unique minute, 2 users with 2 unique minutes, and 0 users for 3, 4, or 5 unique minutes.

Time and Space Complexity

Brute-force approach:

  • For each user, scan all logs to collect their unique minutes.
  • If there are n logs and u users, this is O(u * n).
Optimized approach (hash map and sets):
  • Building the user-minute sets: O(n), as each log is processed once.
  • Counting unique minutes for each user: O(u), where u is the number of users.
  • Overall time: O(n + u)
  • Space: O(n) for storing all unique user-minute pairs.

The optimized approach is efficient and scales well with input size.

Summary

This problem is a great example of how to aggregate and analyze log data efficiently. By using a hash map to associate each user with a set of their unique active minutes, we avoid double-counting and make our solution both simple and fast. The final tally is a straightforward pass over the user data, producing the required summary array. The solution is elegant because it leverages the right data structures for the task and avoids unnecessary computation.

Code Implementation

from collections import defaultdict

def findingUsersActiveMinutes(logs, k):
    user_minutes = defaultdict(set)
    for user, minute in logs:
        user_minutes[user].add(minute)
    answer = [0] * k
    for minutes in user_minutes.values():
        count = len(minutes)
        if 1 <= count <= k:
            answer[count - 1] += 1
    return answer
      
#include <vector>
#include <unordered_map>
#include <unordered_set>

using namespace std;

vector<int> findingUsersActiveMinutes(vector<vector<int>>& logs, int k) {
    unordered_map<int, unordered_set<int>> user_minutes;
    for (const auto& log : logs) {
        user_minutes[log[0]].insert(log[1]);
    }
    vector<int> answer(k, 0);
    for (const auto& pair : user_minutes) {
        int count = pair.second.size();
        if (count >= 1 && count <= k) {
            answer[count - 1]++;
        }
    }
    return answer;
}
      
import java.util.*;

class Solution {
    public int[] findingUsersActiveMinutes(int[][] logs, int k) {
        Map<Integer, Set<Integer>> userMinutes = new HashMap<>();
        for (int[] log : logs) {
            userMinutes.computeIfAbsent(log[0], x -> new HashSet<>()).add(log[1]);
        }
        int[] answer = new int[k];
        for (Set<Integer> minutes : userMinutes.values()) {
            int count = minutes.size();
            if (count >= 1 && count <= k) {
                answer[count - 1]++;
            }
        }
        return answer;
    }
}
      
var findingUsersActiveMinutes = function(logs, k) {
    const userMinutes = new Map();
    for (const [user, minute] of logs) {
        if (!userMinutes.has(user)) userMinutes.set(user, new Set());
        userMinutes.get(user).add(minute);
    }
    const answer = new Array(k).fill(0);
    for (const minutes of userMinutes.values()) {
        const count = minutes.size;
        if (count >= 1 && count <= k) {
            answer[count - 1]++;
        }
    }
    return answer;
};