Skip to main content
Back to problems
#3433
Medium Algorithms

Count mentions per user

Array Math Sorting Simulation
50.8% acceptance
Feb 25, 2026
391
248
You are given an integer numberOfUsers representing the total number of users and an array events of size n x 3. Each events[i] can be either of the following two types: Message Event: ["MESSAGE", "timestampi", "mentions_stringi"] This event indicates that a set of users was mentioned in a message at timestampi. The mentions_stringi string can contain one of the following tokens: id: where is an integer in range [0,numberOfUsers - 1]. There can be multiple ids separated by a single whitespace and may contain duplicates. This can mention even the offline users. ALL: mentions all users. HERE: mentions all online users. Offline Event: ["OFFLINE", "timestampi", "idi"] This event indicates that the user idi had become offline at timestampi for 60 time units. The user will automatically be online again at time timestampi + 60. Return an array mentions where mentions[i] represents the number of mentions the user with id i has across all MESSAGE events. All users are initially online, and if a user goes offline or comes back online, their status change is processed before handling any message event that occurs at the same timestamp. Note that a user can be mentioned multiple times in a single message event, and each mention should be counted separately.

Solution

Rust
Time O(n²)
Space O(n)
LeetCode
solution.rs
impl Solution {
  pub fn count_mentions(number_of_users: i32, events: Vec<Vec<String>>) -> Vec<i32> {
    let nu = number_of_users as usize;
    let mut mentions = vec![0i32; nu];
    let mut offline_until = vec![0i32; nu]; // 0 means online
    // Sort by timestamp, with OFFLINE before MESSAGE at same timestamp
    let mut evts: Vec<&Vec<String>> = events.iter().collect();
    evts.sort_by(|a, b| {
      let ta: i32 = a[1].parse().unwrap();
      let tb: i32 = b[1].parse().unwrap();
      // At equal timestamps, OFFLINE must precede MESSAGE.
      // Alphabetically "MESSAGE" < "OFFLINE", so reverse type comparison to put OFFLINE first.
      ta.cmp(&tb).then(b[0].cmp(&a[0]))
    });
    for e in evts {
      let t: i32 = e[1].parse().unwrap();
      if e[0] == "OFFLINE" {
        let uid: usize = e[2].parse().unwrap();
        offline_until[uid] = t + 60;
      } else { // MESSAGE
        let msg = &e[2];
        if msg == "ALL" {
          for m in mentions.iter_mut() { *m += 1; }
        } else if msg == "HERE" {
          for (i, m) in mentions.iter_mut().enumerate() {
            if offline_until[i] <= t { *m += 1; }
          }
        } else {
          for part in msg.split_whitespace() {
            let uid: usize = part[2..].parse().unwrap();
            mentions[uid] += 1;
          }
        }
      }
    }
    mentions
  }
}